См. обновления внизу (30 апреля 2015 г.)
Я реализую круговую диаграмму в Swift для iOS, используя ios-charts, и решил настроить легенду. Следует отметить, что диаграмма отображается в ячейке UICollectionView. Проблема в том, что при первом отображении пользовательское содержимое легенды не отображается. Вместо этого я получаю содержимое легенды, сгенерированное из данных.
Если я прокручиваю представление за пределами экрана, а затем прокручиваю его обратно на экран, отображается правильная пользовательская легенда. Итак, я предполагаю, что мне нужно принудительно перерисовать/перестроить/переделать что-то после установки пользовательской легенды. Я не понял, как это сделать. У кого-нибудь есть идея? Я что-то совсем упустил? Спасибо!
Диаграмма при первоначальном отображении — легенда, сгенерированная данными (неправильная)
Диаграмма после прокрутки и возврата на экран - (правильная легенда)
Вот мой код для рисования этой диаграммы:
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)
}
Обновление от 30 апреля 2015 г.
Основываясь на обсуждении с автором MPAndroidChart (на котором основаны ios-charts), кажется, что в жизненном цикле отображения диаграммы нет точки, в которой можно переопределить легенду при «первом отрисовке». По сути, диаграмма отображается при ее создании, несмотря ни на что. Если вы устанавливаете данные на диаграмме, диаграмма использует эти данные для создания легенды, а затем отображает. Невозможно изменить легенду между точкой установки данных и точкой отображения диаграммы.
setNeedsDisplay()
Потенциально можно дождаться отображения диаграммы, обновить легенду, а затем вызвать chart.setNeedsDisplay(), чтобы сигнализировать о перерисовке диаграммы. К сожалению, здесь есть проблема со временем. Если вы вызываете этот метод сразу после рендеринга диаграммы, он либо не срабатывает, либо (что более вероятно) срабатывает слишком рано и эффективно игнорируется. В моем коде размещение этого вызова в viewDidLoad или viewDidAppear не имело никакого эффекта. Однако...
Создание той же диаграммы в Java для Android (с использованием MPAndroidChart) приводит к той же проблеме. Немного повозившись, я заметил, что если я вызову функцию chart.invalidate() после задержки (используя Handler.postDelayed()), она сработает правильно. Оказывается, аналогичный подход работает и для ios-чартов на iOS.
Если кто-то использует GCD для задержки вызова setNeedsDisplay() даже на несколько миллисекунд после рендеринга, кажется, что это помогает. Я добавил следующий код сразу после инициализации представления диаграммы в моем ViewController («ячейка» — это 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: https://stackoverflow.com/a/24318861
Очевидно, это неприятный хак, но, похоже, он помогает. Однако я не уверен, что мне нравится идея использовать этот хак в продакшене.
Для всех пользователей Android, которые наткнулись на этот пост:
Следующий код достигает того же эффекта с помощью 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);