2015-04-30 4 views
6

Mises à jour Voir en bas (4/30/2015)ios-graphiques Comment invalident/redessiner après les données de réglage

Je mettre en œuvre un diagramme circulaire à Swift pour iOS à l'aide ios-graphiques, et ont choisi personnaliser la légende À noter, le graphique est affiché dans une cellule d'un UICollectionView. Le problème est que sur le premier affichage, le contenu de la légende personnalisée n'est pas affiché. Au lieu de cela, je reçois le contenu de la légende généré à partir des données.

Si je fais défiler la vue hors de l'écran et que je la fais défiler sur l'écran, la légende personnalisée appropriée s'affiche. Donc, je suis devinant que j'ai besoin de forcer un redraw/relayout/re-quelque chose après avoir défini ma légende personnalisée. Je n'ai pas compris comment faire ça. Est-ce que quelqu'un a une idée? Est-ce que je manque complètement quelque chose? Merci!

graphique sur l'affichage initial - données générées (mauvaise) légende Chart on initial display - generated legend

graphique après avoir fait défiler hors tension et sur l'écran - (légende appropriée) Chart with proper legend

Voici mon code dessin ce tableau:

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) 
} 

Mise à jour 4/30/2015

Sur la base de discussion avec l'auteur de MPAndroidChart (sur lequel repose ios-graphiques), il semble qu'il n'y a pas un point dans le cycle de vie d'affichage graphique où l'on peut remplacer la légende « premier dessiner". Fondamentalement, le tableau est rendu quand il est créé, peu importe quoi. Si vous définissez des données sur le graphique, le graphique utilise ces données pour créer la légende, puis les restitue. Il n'est pas possible de modifier la légende entre le point de définition des données et le point de rendu du graphique.

setNeedsDisplay()

potentiellement, on peut attendre le graphique pour rendre, mettre à jour la légende, puis appelez chart.setNeedsDisplay() pour signaler le graphique pour redessiner. Malheureusement, il y a un problème de synchronisation avec cela. Si vous appelez cette méthode immédiatement après avoir rendu le graphique, il ne se déclenche pas ou (plus probablement) il se déclenche trop tôt et est effectivement ignoré. Dans mon code, placer cet appel dans viewDidLoad ou viewDidAppear n'a eu aucun effet. Cependant ...

Construire le même graphique en Java pour Android (en utilisant MPAndroidChart) entraîne le même problème. Après avoir déconné un peu, j'ai noté que si j'appelais chart.invalidate() après un délai (en utilisant Handler.postDelayed()), il se déclencherait correctement. Il se trouve qu'une approche similaire fonctionne pour ios-charts sur iOS.

Si on utilise GCD pour retarder l'appel de setNeedsDisplay(), même quelques millisecondes après le rendu, cela semble faire l'affaire. J'ai ajouté le code suivant immédiatement après l'initialisation dans mon ViewController (« cellule » est le UICollectionViewCell contenant la vue graphique) Selon le tableau:

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() 
} 

En utilisant la méthode « de retard » impressionnant de ce SO message: https://stackoverflow.com/a/24318861

De toute évidence, c'est un hack méchant, mais il semble faire l'affaire. Cependant, je ne suis pas sûr d'aimer l'idée d'utiliser ce hack dans la production.

Pour toute populaire Android qui trébuchent sur ce post:

Le code suivant obtient le même effet en utilisant 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); 
+2

Avez-vous essayé d'ajouter simplement pieChart.setNeedsDisplay() à la fin de la méthode viewDidLoad()? –

+0

@Shawn Oui, j'ai fait un essai (à partir de nombreux points dans le code), mais pas de joie. Le cycle de vie de l'affichage de graphique dans la bibliothèque MPAndroidCharts, sur lequel il est basé, affiche le graphique sur la vue init et lorsque les données sont définies. Solvable via chart.invalidate() (après délai), mais cette méthode n'est pas dans le port ios-chart. Aucune solution pour le moment, mais je vais essayer quelques autres choses et mettre à jour la question avec tout ce que je découvre. – MojoTosh

Répondre

7

Je suis l'auteur de ios-graphiques, et nous sommes travailler sur les fonctionnalités de personnalisation des données de légende, sans ces "hacks".

Dans le dernier engage ios-graphiques, vous pouvez déjà voir extraLabels et extraColors propriétés qui ajoutent des lignes supplémentaires à la légende, et une fonction setLegend qui vous permet de définir des données personnalisées entièrement.

Ce sera bientôt ajouté à la version Android.

Profitez :-)

+0

des nouvelles de ce problème? –

+0

Résolu il y a longtemps ... –

+0

@ daniel.gindi Fellow israélien ici! Merci d'avoir fait cette géniale bibliothèque! Pourriez-vous jeter un coup d'œil à ma question par hasard s'il vous plaît? http://stackoverflow.com/questions/43463040/show-only-last-n-bars-ios-charts – MarksCode