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

См. Обновления в нижней части (30.04.2015)

Я внедряю круговую диаграмму в Swift для iOS, используя ios-диаграммы, и решил настроить легенду. Следует отметить, что диаграмма отображается в ячейке 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.04.2015

Основываясь на обсуждении с автором MPAndroidChart (на котором основаны ios-диаграммы), оказалось, что в жизненном цикле отображения диаграммы нет точки, где можно было бы переопределить легенду при "первом рисовании". По сути, диаграмма отображается при ее создании, несмотря ни на что. Если вы устанавливаете данные на диаграмме, диаграмма использует эти данные для создания легенды, а затем выполняет рендеринг. Невозможно изменить легенду между точкой задания данных и точкой рендеринга диаграммы.

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: /questions/21142376/dispatchafter-gcd-v-byistrom/21142389#21142389

Очевидно, что это противный хак, но, похоже, он добился цели. Я не уверен, что мне нравится идея использовать этот хак в производстве.

Для любого пользователя 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);

1 ответ

Решение

Я являюсь автором ios-диаграмм, и мы работаем над функциями для настройки данных легенды без этих "хаков".

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

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

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

Другие вопросы по тегам