无法使图表对象在自定义UIView中工作

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了无法使图表对象在自定义UIView中工作相关的知识,希望对你有一定的参考价值。

我正在使用Daniel Gindi的图表库(ios图表),为了简单起见,我使用自定义UIView来存储图表视图(作为ChartViewBase)。我有一个View Controller类的类层次结构,其中leaf类具有对其中包含ChartViewBase的UIView的引用。问题是图表拒绝显示,我得到的只是图表应该是的黑色矩形。我想代码可能是最有用的,所以这里什么都没有: 通用的UIView图表保持类:

import UIKit
import Charts

protocol GenericChartViewDelegate: class {
func backButtonTapped()
func switchChartButtonTapped()
func finalizeResultsButtonTapped()
}

class GenericChartView: UIView, ChartViewDelegate
{

@IBOutlet weak var headerDisplay: UIButton!
@IBOutlet var view: UIView!
weak var delegate: GenericChartViewDelegate?
required init?(coder aDecoder: NSCoder)
{
    super.init(coder: aDecoder)
    Bundle.main.loadNibNamed("GenericChartView", owner: self, options: nil)
    self.addSubview(self.view)
    chart.delegate = self
}
override init(frame: CGRect)
{
    super.init(frame: frame)
    Bundle.main.loadNibNamed("GenericChartView", owner: self, options: nil)
    self.addSubview(self.view)
    chart.delegate = self
}
@IBOutlet var chart: ChartViewBase!
@IBAction func BackButton(_ sender: UIButton) {
    delegate?.backButtonTapped()
}

@IBAction func SwitchChartButton(_ sender: UIButton) {
    delegate?.switchChartButtonTapped()
}

@IBAction func FinalizeResultsButton(_ sender: UIButton) {
    delegate?.finalizeResultsButtonTapped()
}
func setHeader(header: String)
{
    headerDisplay.setTitle(header, for: UIControlState.normal)
    headerDisplay.layer.cornerRadius = MyVariables.borderCurvature
    headerDisplay.titleLabel?.adjustsFontSizeToFitWidth = true

}
}

现在基础图表视图控制器:

class ChartViewControllerBase: UIViewController
{

var myColors : [NSUIColor] = []
//var bounds : CGRect!
override func viewDidLoad() {
    super.viewDidLoad()
    let sessionCount = ShareData.sharedInstance.currentSessionNumber
    //NotificationCenter.default.addObserver(self, selector: "rotated", name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
    createChart()
    var myBase = getChartObject()

    var myChartView = getChartDisplayView()
    setDelegate()
    if let myName = ShareData.sharedInstance.currentAccount.name {//sessionName.characters.last!
        let myTitle = "Session " + "(sessionCount)" + " Results - " + myName

        myChartView.setHeader(header: myTitle)
    }

    //chartOriginalBounds = chart.bounds
    if let resultChoice = ShareData.sharedInstance.sessionDataObjectContainer[ShareData.sharedInstance.currentAccountSessionNames[sessionCount - 1]]?.chartInfo
    {
        makeChart(resultChoice: resultChoice)
    }

    // Do any additional setup after loading the view.
}

func setDelegate()
{

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}
func createChart()
{

}
func getChartDisplayView() -> GenericChartView
{
    return GenericChartView(frame: self.view.bounds)
}

func getChartObject() -> ChartViewBase
{
    return ChartViewBase()
}

func makeChart(resultChoice: chartData)
{

}

func getColors(value: Double)
{

}

func getChartDataEntry(xval: Double, yval: Double) -> ChartDataEntry
{
    return ChartDataEntry(x: xval, y: yval)
}
}

现在LineAndBarChart代码:

class LineAndBarChartViewControllerBase: ChartViewControllerBase {

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

override func getChartObject() -> ChartViewBase
{
    return ChartViewBase()
}
var yAxis: YAxis!

func setYAxisFormatter() {

}

func createSet(myEntries: [ChartDataEntry])
{

}



override func makeChart(resultChoice: chartData)
{
    let chart = getChartObject() as! BarLineChartViewBase
    chart.chartDescription?.enabled = false
    chart.drawGridBackgroundEnabled = false
    chart.dragEnabled = true
    chart.setScaleEnabled(true)
    chart.pinchZoomEnabled = true
    let xAxis = chart.xAxis
    xAxis.labelPosition = XAxis.LabelPosition.bottom
    chart.rightAxis.enabled = false
    xAxis.drawGridLinesEnabled = false
    xAxis.drawAxisLineEnabled = true
    xAxis.granularity = 1.0


    //xAxis.setValuesForKeys(<#T##keyedValues: [String : Any]##[String : Any]#>)
    yAxis = chart.leftAxis
    chart.rightAxis.enabled = false
    chart.legend.enabled = true
    yAxis.granularity = 1.0
    yAxis.drawGridLinesEnabled = false
    var counter = 1.0
    var myEntries : [ChartDataEntry] = []

    var myXValues : [String] = []


    if !resultChoice.plotPoints.isEmpty
    {
        for var item in resultChoice.plotPoints
        {
            let timeString : String =
                {
                    let formatter = DateFormatter()
                    formatter.dateFormat = "h:mm a"
                    formatter.amSymbol = "AM"
                    formatter.pmSymbol = "PM"
                    return formatter.string(from: item.xValue)
            }()
            myXValues.append(timeString)
            /*if(item.showXValue)
             {
             myXValues.append(timeString)
             }
             else
             {
             myXValues.append("")
             }*/
            let myEntry = getChartDataEntry(xval: counter, yval: Double(item.yValue))
            getColors(value: myEntry.y)

            counter += 1
            myEntries.append(myEntry)

        }
        let myFormatter = MyXAxisValueFormatter(values: myXValues)

        xAxis.valueFormatter = myFormatter
        setYAxisFormatter()
        createSet(myEntries: myEntries)

    }

}
}

class MyXAxisValueFormatter: NSObject, IAxisValueFormatter {

var mValues: [String]

init(values: [String]) {
    self.mValues = values;
}


func stringForValue( _ value: Double, axis: AxisBase?) -> String
{
    // "value" represents the position of the label on the axis (x or y)
    let myVal: Int = Int(value)
    if (myVal < mValues.count)
    {
        return mValues[myVal];
    }
    else
    {
        return "ERROR"
    }
}
}

然后条形图基本代码:

class BarChartViewControllerBase: LineAndBarChartViewControllerBase {

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}



override func createChart()
{
    var myChart = getChartDisplayView()
    myChart.chart = BarChartView(frame: myChart.chart.contentRect)
}

override func createSet(myEntries: [ChartDataEntry])
{
    let chart = getChartObject() as! BarChartView
    let mySet = BarChartDataSet(values: myEntries, label: "Values")
    mySet.colors = myColors
    mySet.valueColors = myColors
    setValueFormatter(set: mySet)

    let myBarChartData = BarChartData(dataSet: mySet)
    myBarChartData.barWidth = 0.8
    chart.data = myBarChartData
}

func setValueFormatter(set: BarChartDataSet)
{

}


override func getChartDataEntry(xval: Double, yval: Double) -> ChartDataEntry
{
    return BarChartDataEntry(x: xval, y: yval)
}
}

最后,叶子(大多数派生类)代码:

class DerivedClassChartViewController: BarChartViewControllerBase, GenericChartViewDelegate
{


@IBOutlet weak var chartView: GenericChartView!
override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


override func getChartDisplayView() -> GenericChartView
{
    return chartView
}

override func getChartObject() -> ChartViewBase
{
    return chartView.chart
}

override func getColors(value: Double)
{
    if (value == 0.0)
    {
        myColors.append(UIColor.black)
    }
    else if (value == 1.0)
    {
        myColors.append(MyVariables.colorOne)
    }
    else if (value == 2.0)
    {
        myColors.append(MyVariables.colorTwo)
    }
    else if (value == 3.0)
    {
        myColors.append(MyVariables.colorThree)
    }
    else if (value == 4.0)
    {
        myColors.append(MyVariables.colorFour)
    }
    else if (value == 5.0)
    {
        myColors.append(MyVariables.colorFive)
    }
}

func backButtonTapped()
{
    self.navigationController?.popViewController(animated: false)
}
func switchChartButtonTapped()
{
    let alertController = UIAlertController(title: nil, message: nil, preferredStyle: UIAlertControllerStyle.actionSheet)
    let goToLineChartAction = UIAlertAction(title: "Line Chart", style: UIAlertActionStyle.default)
    { (alertAction: UIAlertAction!) -> Void in
        self.navigationController?.popViewController(animated: false)
       let viewControllerStoryboardId = "LineChartDisplayViewController"
        let storyboardName = "Main"
        let storyboard = UIStoryboard(name: storyboardName, bundle: Bundle.main)
        let viewController = storyboard.instantiateViewController(withIdentifier: viewControllerStoryboardId)
        self.navigationController?.pushViewController(viewController, animated: false)
    }
    alertController.addAction(goToLineChartAction)
    alertController.view.tintColor = UIColor.black
    present(alertController, animated: true, completion:  nil)
    let presentationController = alertController.popoverPresentationController
    presentationController?.sourceView = self.view
    presentationController?.sourceRect = CGRect(x: 330, y: 210, width: 330, height: 210)
}
func finalizeResultsButtonTapped()
{

}

override func setDelegate()
{
    chartView.delegate = self
}
override func setValueFormatter(set: BarChartDataSet)
{
    set.valueFormatter = DerivedClassNumberFormatter()
}
}

class DerivedClassNumberFormatter: NSObject, IValueFormatter {
func stringForValue(_ value: Double, entry: ChartDataEntry, dataSetIndex: Int, viewPortHandler: ViewPortHandler?) -> String {
    var returnVal = "(Int(value))"

    return returnVal
}
}

我有几个问题。你是否将UIView设为ChartViewDelegate,还是应该是包含保存图表对象的UIView的视图控制器?我错过了什么明显的东西?我之前使用过自定义UIViews,所以我知道该代码是正确的(除了类是否应该是ChartViewDelegate,这是 - 我不知道)。是的,我确实需要所有这些课程,因为将来会有很多很多图表类型。无论如何,关于我可以做什么来获得图表的任何建议都会很棒。

谢谢, 肖恩

答案

我也在使用图表库。我不确定我是否完全理解你的限制,但我能够在自定义UIView中包含图表。我有其他方法(未显示)将实际数据从视图控制器传递到标签和图表。

我是这样做的:

import UIKit
import Charts

class MyHeader: UIView, ChartViewDelegate {

// My Header is the top view of the ViewController
// It gives summary information for the user

// MARK: - Properties
var firstLabel = LabelView()
var secondLabel = LabelView()
var firstPie = PieChartView()
var secondPie = PieChartView()
var thirdPie = PieChartView()
let nformatter = NumberFormatter()

// MARK: - LifeCycle
override func awakeFromNib() {
    super.awakeFromNib()
}

override init(frame: CGRect) {
    super.init(frame: frame)

    self.backgroundColor = UIColor.white.withAlphaComponent(0.5)
    setupStack()
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

// MARK: - Setup Methods

func setupLabels() {
    let lbls = [firstLabel, secondLabel]
    for lbl in lbls {
        lbl.label.font = UIFont.preferredFont(forTextStyle: .title3)
        lbl.translatesAutoresizingMaskIntoConstraints = false
        lbl.heightAnchor.constraint(equalToConstant: 50).isActive = true
    }
    let pies = [firstPie, secondPie, thirdPie]
    for pie in pies {
        pie.translatesAutoresizingMaskIntoConstraints = false
        pie.heightAnchor.constraint(equalToConstant: 100).isActive = true
        pie.spanSuperView()  // spanSuperView is a UIView extension that I use
        pie.delegate = self as ChartViewDelegate
        // entry label styling
        pie.entryLabelColor = .white
        pie.entryLabelFont = .systemFont(ofSize: 12, weight: .light)
        pie.animate(xAxisDuration: 1.4, easingOption: .easeOutBack)
    }
}

func setupFake() {

    let months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
    let unitsSold = [20.0, 4.0, 6.0, 3.0, 12.0, 16.0]

    setChart(dataPoints: months, values: unitsSold)
}

func setChart(dataPoints: [String], values: [Double]) {

    var dataEntries: [ChartDataEntry] = []

    for i in 0..<dataPoints.count {
        let dataEntry = ChartDataEntry(x: values[i], y: Double(i))
        dataEntries.append(dataEntry)
    }

    let set = PieChartDataSet(values: dataEntries, label: "Results")
    set.drawIconsEnabled = false
    set.sliceSpace = 2


    set.colors = ChartColorTemplates.joyful()
        + ChartColorTemplates.colorful()
        + ChartColorTemplates.liberty()
        + ChartColorTemplates.pastel()
        + [UIColor(red: 51/255, green: 181/255, blue: 229/255, alpha: 1)]

    let data = PieChartData(dataSet: set)
    let pies = [firstPie, secondPie, thirdPie]
    for pie in pies {
        pie.data = data
    }

}



func setupStack(){
    setupFake()
    setupLabels()
    let dashStack = UIStackView(arrangedSubviews: [firstPie, secondPie, thirdPie])
    dashStack.axis = .horizontal
    dashStack.distribution = .fillEqually
    dashStack.alignment = .center
    dashStack.spacing = 0
    dashStack.translatesAutoresizingMaskIntoConstraints = false


    let stackView = UIStackView(arrangedSubviews: [firstLabel, secondLabel, dashStack])
    stackView.axis = .vertical
    stackView.distribution = .fill
    stackView.alignment = .fill
    stackView.spacing = 0
    stackView.translatesAutoresizingMaskIntoConstraints = false

    self.addSubview(stackView)
    //autolayout the stack view
    stackView.spanSuperView()
}
}

以上是关于无法使图表对象在自定义UIView中工作的主要内容,如果未能解决你的问题,请参考以下文章

UIView核心动画无法在viewdidLoad方法中工作?

无法使 PHP 函数在 PHP 内部的 HTML 中工作

无法使 onClick 在 ReactJS 中工作

如何使 Snackbar 在类组件中工作?

使对象适合和对象位置在 Internet Explorer 中工作

无法让闭包语法在 swift 4 中工作