ios-charts Как аннулировать/перерисовать после установки данных

См. обновления внизу (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);

person MojoTosh    schedule 30.04.2015    source источник
comment
Вы пытались просто добавить pieChart.setNeedsDisplay() в конце метода viewDidLoad()?   -  person R.Lambert    schedule 30.04.2015
comment
@Shawn Да, я попробовал (из многих моментов в коде), но без удовольствия. Жизненный цикл отображения диаграммы в библиотеке MPAndroidCharts, на которой он основан, отображает диаграмму при инициализации представления и при установке данных. Решается через chart.invalidate() (после задержки), но этого метода нет в порте ios-chart. Пока нет решения, но я попробую еще несколько вещей и обновлю вопрос тем, что узнаю.   -  person MojoTosh    schedule 30.04.2015


Ответы (1)


Я автор ios-charts, и мы работаем над возможностью настройки данных легенды без этих «хаков».

В последних коммитах для ios-charts уже можно увидеть свойства extraLabels и extraColors, добавляющие дополнительные строки в легенду, и функцию setLegend, позволяющую полностью задавать пользовательские данные.

Вскоре это будет добавлено и в версию для Android.

Наслаждаться :-)

person daniel.gindi    schedule 19.05.2015
comment
есть новости по этой проблеме? - person sliwinski.lukas; 30.08.2016
comment
@daniel.gindi Товарищ израильтянин здесь! Спасибо за создание этой замечательной библиотеки! Не могли бы вы взглянуть на мой вопрос случайно, пожалуйста? stackoverflow.com/questions/43463040 / - person MarksCode; 18.04.2017