ios-图表设置数据后如何invalidate/redraw
ios-charts How to invalidate/redraw after setting data
查看底部更新 (4/30/2015)
我正在 Swift 中使用 ios 图表为 iOS 实现饼图,并选择自定义图例。值得注意的是,图表显示在 UICollectionView 的单元格中。问题是在第一次显示时,没有显示自定义图例内容。相反,我得到了从数据生成的图例内容。
如果我将视图滚动到屏幕外,然后再将其滚动回屏幕上,则会显示正确的自定义图例。所以,我 猜测我需要在设置自定义图例后强制执行 redraw/relayout/re-something。我还不知道该怎么做。 有谁知道吗?我完全错过了什么吗?谢谢!
初始显示的图表 - 数据生成的(错误的)图例
滚动并返回屏幕后的图表 -(正确的图例)
这是我绘制此图表的代码:
func initChart(pieChart: PieChartView) {
numFormatter.maximumFractionDigits = 0
pieChart.backgroundColor = UIColor.whiteColor()
pieChart.usePercentValuesEnabled = false
pieChart.drawHoleEnabled = true
pieChart.holeTransparent = true
pieChart.descriptionText = ""
pieChart.centerText = "30%\nComplete"
pieChart.data = getMyData()
// Setting custom legend info, called AFTER setting data
pieChart.legend.position = ChartLegend.ChartLegendPosition.LeftOfChartCenter
pieChart.legend.colors = [clrGreenDk, clrGold, clrBlue]
pieChart.legend.labels = ["Complete","Enrolled","Future"]
pieChart.legend.enabled = true
}
func getMyData() -> ChartData {
var xVals = ["Q201","R202","S203","T204","U205", "V206"]
var courses: [ChartDataEntry] = []
courses.append(ChartDataEntry(value: 3, xIndex: 0))
courses.append(ChartDataEntry(value: 3, xIndex: 1))
courses.append(ChartDataEntry(value: 4, xIndex: 2))
courses.append(ChartDataEntry(value: 4, xIndex: 3))
courses.append(ChartDataEntry(value: 3, xIndex: 4))
courses.append(ChartDataEntry(value: 3, xIndex: 5))
let dsColors = [clrGreenDk, clrGreenDk, clrBlue, clrBlue, clrGold, clrGold]
let pcds = PieChartDataSet(yVals: courses, label: "")
pcds.sliceSpace = CGFloat(4)
pcds.colors = dsColors
pcds.valueFont = labelFont!
pcds.valueFormatter = numFormatter
pcds.valueTextColor = UIColor.whiteColor()
return ChartData(xVals: xVals, dataSet: pcds)
}
2015 年 4 月 30 日更新
根据与 MPAndroidChart(ios-charts 所基于的)作者的讨论,似乎在图表显示生命周期中没有一个点可以覆盖图例在 "first draw" 上。基本上,图表在创建时呈现,无论如何。如果您在图表上设置数据,图表会使用该数据创建图例,然后呈现。无法更改设置数据点和图表渲染点之间的图例。
setNeedsDisplay()
可能,可以等待图表呈现、更新图例,然后调用 chart.setNeedsDisplay() 以指示图表重绘。可悲的是,这有一个时间问题。如果您在呈现图表后立即调用此方法,它要么不会触发,要么(更有可能)触发得太早而被有效地忽略。在我的代码中,将此调用放在 viewDidLoad 或 viewDidAppear 中没有任何效果。然而...
在 Java 中为 Android 构建相同的图表(使用 MPAndroidChart)会导致相同的问题。稍微弄乱之后,我注意到如果我在延迟后调用 chart.invalidate()(使用 Handler.postDelayed()),它会正常触发。事实证明,类似的方法适用于 iOS 上的 ios-图表。
如果使用 GCD 来延迟对 setNeedsDisplay() 的调用,即使在渲染后延迟几毫秒,似乎也能达到目的。在 ViewController 中初始化图表视图后,我立即添加了以下代码("cell" 是包含图表视图的 UICollectionViewCell):
delay(0.05) {
cell.pieChartView.legend.colors = [self.clrGreenDk, self.clrGold, self.clrBlue]
cell.pieChartView.legend.labels = ["Complete","Enrolled","Future"]
// Re-calc legend dimensions for proper position (Added 5/2/2015)
cell.pieChartView.legend.calculateDimensions(cell.pieChartView.labelFont!)
cell.pieChartView.setNeedsDisplay()
}
使用来自这个 SO post 的很棒的 "delay" 方法:
显然,这是一个令人讨厌的 hack,但它似乎可以解决问题。不过,我不确定我是否喜欢在生产中使用这个 hack 的想法。
对于任何 Android 偶然发现此问题的人 post:
以下代码使用 MPAndroidChart 实现相同的效果:
// Inside onCreate()
pie = (PieChart) findViewById(R.id.chart1);
configPieChart(pie);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
String[] legLabels = new String[]{"Complete","Enrolled","Future"};
ArrayList<Integer> legColors = new ArrayList<Integer>();
legColors.add(blue);
legColors.add(gold);
legColors.add(green);
pie.getLegend().setPosition(Legend.LegendPosition.LEFT_OF_CHART_CENTER);
pie.getLegend().setColors(legColors);
pie.getLegend().setLabels(legLabels);
pie.invalidate();
}
}, 20);
我是 ios-charts 的作者,我们正在开发自定义图例数据的功能,没有那些 "hacks"。
在 ios-charts 的最新提交中,您已经可以看到 extraLabels
和 extraColors
向图例添加额外线条的属性,以及 setLegend
函数允许您完全设置自定义数据。
这也将很快添加到 Android 版本中。
享受:-)
查看底部更新 (4/30/2015)
我正在 Swift 中使用 ios 图表为 iOS 实现饼图,并选择自定义图例。值得注意的是,图表显示在 UICollectionView 的单元格中。问题是在第一次显示时,没有显示自定义图例内容。相反,我得到了从数据生成的图例内容。
如果我将视图滚动到屏幕外,然后再将其滚动回屏幕上,则会显示正确的自定义图例。所以,我 猜测我需要在设置自定义图例后强制执行 redraw/relayout/re-something。我还不知道该怎么做。 有谁知道吗?我完全错过了什么吗?谢谢!
初始显示的图表 - 数据生成的(错误的)图例
滚动并返回屏幕后的图表 -(正确的图例)
这是我绘制此图表的代码:
func initChart(pieChart: PieChartView) {
numFormatter.maximumFractionDigits = 0
pieChart.backgroundColor = UIColor.whiteColor()
pieChart.usePercentValuesEnabled = false
pieChart.drawHoleEnabled = true
pieChart.holeTransparent = true
pieChart.descriptionText = ""
pieChart.centerText = "30%\nComplete"
pieChart.data = getMyData()
// Setting custom legend info, called AFTER setting data
pieChart.legend.position = ChartLegend.ChartLegendPosition.LeftOfChartCenter
pieChart.legend.colors = [clrGreenDk, clrGold, clrBlue]
pieChart.legend.labels = ["Complete","Enrolled","Future"]
pieChart.legend.enabled = true
}
func getMyData() -> ChartData {
var xVals = ["Q201","R202","S203","T204","U205", "V206"]
var courses: [ChartDataEntry] = []
courses.append(ChartDataEntry(value: 3, xIndex: 0))
courses.append(ChartDataEntry(value: 3, xIndex: 1))
courses.append(ChartDataEntry(value: 4, xIndex: 2))
courses.append(ChartDataEntry(value: 4, xIndex: 3))
courses.append(ChartDataEntry(value: 3, xIndex: 4))
courses.append(ChartDataEntry(value: 3, xIndex: 5))
let dsColors = [clrGreenDk, clrGreenDk, clrBlue, clrBlue, clrGold, clrGold]
let pcds = PieChartDataSet(yVals: courses, label: "")
pcds.sliceSpace = CGFloat(4)
pcds.colors = dsColors
pcds.valueFont = labelFont!
pcds.valueFormatter = numFormatter
pcds.valueTextColor = UIColor.whiteColor()
return ChartData(xVals: xVals, dataSet: pcds)
}
2015 年 4 月 30 日更新
根据与 MPAndroidChart(ios-charts 所基于的)作者的讨论,似乎在图表显示生命周期中没有一个点可以覆盖图例在 "first draw" 上。基本上,图表在创建时呈现,无论如何。如果您在图表上设置数据,图表会使用该数据创建图例,然后呈现。无法更改设置数据点和图表渲染点之间的图例。
setNeedsDisplay()
可能,可以等待图表呈现、更新图例,然后调用 chart.setNeedsDisplay() 以指示图表重绘。可悲的是,这有一个时间问题。如果您在呈现图表后立即调用此方法,它要么不会触发,要么(更有可能)触发得太早而被有效地忽略。在我的代码中,将此调用放在 viewDidLoad 或 viewDidAppear 中没有任何效果。然而...
在 Java 中为 Android 构建相同的图表(使用 MPAndroidChart)会导致相同的问题。稍微弄乱之后,我注意到如果我在延迟后调用 chart.invalidate()(使用 Handler.postDelayed()),它会正常触发。事实证明,类似的方法适用于 iOS 上的 ios-图表。
如果使用 GCD 来延迟对 setNeedsDisplay() 的调用,即使在渲染后延迟几毫秒,似乎也能达到目的。在 ViewController 中初始化图表视图后,我立即添加了以下代码("cell" 是包含图表视图的 UICollectionViewCell):
delay(0.05) {
cell.pieChartView.legend.colors = [self.clrGreenDk, self.clrGold, self.clrBlue]
cell.pieChartView.legend.labels = ["Complete","Enrolled","Future"]
// Re-calc legend dimensions for proper position (Added 5/2/2015)
cell.pieChartView.legend.calculateDimensions(cell.pieChartView.labelFont!)
cell.pieChartView.setNeedsDisplay()
}
使用来自这个 SO post 的很棒的 "delay" 方法:
显然,这是一个令人讨厌的 hack,但它似乎可以解决问题。不过,我不确定我是否喜欢在生产中使用这个 hack 的想法。
对于任何 Android 偶然发现此问题的人 post:
以下代码使用 MPAndroidChart 实现相同的效果:
// Inside onCreate()
pie = (PieChart) findViewById(R.id.chart1);
configPieChart(pie);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
String[] legLabels = new String[]{"Complete","Enrolled","Future"};
ArrayList<Integer> legColors = new ArrayList<Integer>();
legColors.add(blue);
legColors.add(gold);
legColors.add(green);
pie.getLegend().setPosition(Legend.LegendPosition.LEFT_OF_CHART_CENTER);
pie.getLegend().setColors(legColors);
pie.getLegend().setLabels(legLabels);
pie.invalidate();
}
}, 20);
我是 ios-charts 的作者,我们正在开发自定义图例数据的功能,没有那些 "hacks"。
在 ios-charts 的最新提交中,您已经可以看到 extraLabels
和 extraColors
向图例添加额外线条的属性,以及 setLegend
函数允许您完全设置自定义数据。
这也将很快添加到 Android 版本中。
享受:-)