• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.github.mikephil.charting.components;
2 
3 import android.graphics.DashPathEffect;
4 import android.graphics.Paint;
5 
6 import com.github.mikephil.charting.utils.ColorTemplate;
7 import com.github.mikephil.charting.utils.FSize;
8 import com.github.mikephil.charting.utils.Utils;
9 import com.github.mikephil.charting.utils.ViewPortHandler;
10 
11 import java.util.ArrayList;
12 import java.util.List;
13 
14 /**
15  * Class representing the legend of the chart. The legend will contain one entry
16  * per color and DataSet. Multiple colors in one DataSet are grouped together.
17  * The legend object is NOT available before setting data to the chart.
18  *
19  * @author Philipp Jahoda
20  */
21 public class Legend extends ComponentBase {
22 
23     public enum LegendForm {
24         /**
25          * Avoid drawing a form
26          */
27         NONE,
28 
29         /**
30          * Do not draw the a form, but leave space for it
31          */
32         EMPTY,
33 
34         /**
35          * Use default (default dataset's form to the legend's form)
36          */
37         DEFAULT,
38 
39         /**
40          * Draw a square
41          */
42         SQUARE,
43 
44         /**
45          * Draw a circle
46          */
47         CIRCLE,
48 
49         /**
50          * Draw a horizontal line
51          */
52         LINE
53     }
54 
55     public enum LegendHorizontalAlignment {
56         LEFT, CENTER, RIGHT
57     }
58 
59     public enum LegendVerticalAlignment {
60         TOP, CENTER, BOTTOM
61     }
62 
63     public enum LegendOrientation {
64         HORIZONTAL, VERTICAL
65     }
66 
67     public enum LegendDirection {
68         LEFT_TO_RIGHT, RIGHT_TO_LEFT
69     }
70 
71     /**
72      * The legend entries array
73      */
74     private LegendEntry[] mEntries = new LegendEntry[]{};
75 
76     /**
77      * Entries that will be appended to the end of the auto calculated entries after calculating the legend.
78      * (if the legend has already been calculated, you will need to call notifyDataSetChanged() to let the changes take effect)
79      */
80     private LegendEntry[] mExtraEntries;
81 
82     /**
83      * Are the legend labels/colors a custom value or auto calculated? If false,
84      * then it's auto, if true, then custom. default false (automatic legend)
85      */
86     private boolean mIsLegendCustom = false;
87 
88     private LegendHorizontalAlignment mHorizontalAlignment = LegendHorizontalAlignment.LEFT;
89     private LegendVerticalAlignment mVerticalAlignment = LegendVerticalAlignment.BOTTOM;
90     private LegendOrientation mOrientation = LegendOrientation.HORIZONTAL;
91     private boolean mDrawInside = false;
92 
93     /**
94      * the text direction for the legend
95      */
96     private LegendDirection mDirection = LegendDirection.LEFT_TO_RIGHT;
97 
98     /**
99      * the shape/form the legend colors are drawn in
100      */
101     private LegendForm mShape = LegendForm.SQUARE;
102 
103     /**
104      * the size of the legend forms/shapes
105      */
106     private float mFormSize = 8f;
107 
108     /**
109      * the size of the legend forms/shapes
110      */
111     private float mFormLineWidth = 3f;
112 
113     /**
114      * Line dash path effect used for shapes that consist of lines.
115      */
116     private DashPathEffect mFormLineDashEffect = null;
117 
118     /**
119      * the space between the legend entries on a horizontal axis, default 6f
120      */
121     private float mXEntrySpace = 6f;
122 
123     /**
124      * the space between the legend entries on a vertical axis, default 5f
125      */
126     private float mYEntrySpace = 0f;
127 
128     /**
129      * the space between the legend entries on a vertical axis, default 2f
130      * private float mYEntrySpace = 2f; /** the space between the form and the
131      * actual label/text
132      */
133     private float mFormToTextSpace = 5f;
134 
135     /**
136      * the space that should be left between stacked forms
137      */
138     private float mStackSpace = 3f;
139 
140     /**
141      * the maximum relative size out of the whole chart view in percent
142      */
143     private float mMaxSizePercent = 0.95f;
144 
145     /**
146      * default constructor
147      */
Legend()148     public Legend() {
149 
150         this.mTextSize = Utils.convertDpToPixel(10f);
151         this.mXOffset = Utils.convertDpToPixel(5f);
152         this.mYOffset = Utils.convertDpToPixel(3f); // 2
153     }
154 
155     /**
156      * Constructor. Provide entries for the legend.
157      *
158      * @param entries
159      */
Legend(LegendEntry[] entries)160     public Legend(LegendEntry[] entries) {
161         this();
162 
163         if (entries == null) {
164             throw new IllegalArgumentException("entries array is NULL");
165         }
166 
167         this.mEntries = entries;
168     }
169 
170     /**
171      * This method sets the automatically computed colors for the legend. Use setCustom(...) to set custom colors.
172      *
173      * @param entries
174      */
setEntries(List<LegendEntry> entries)175     public void setEntries(List<LegendEntry> entries) {
176         mEntries = entries.toArray(new LegendEntry[entries.size()]);
177     }
178 
getEntries()179     public LegendEntry[] getEntries() {
180         return mEntries;
181     }
182 
183     /**
184      * returns the maximum length in pixels across all legend labels + formsize
185      * + formtotextspace
186      *
187      * @param p the paint object used for rendering the text
188      * @return
189      */
getMaximumEntryWidth(Paint p)190     public float getMaximumEntryWidth(Paint p) {
191 
192         float max = 0f;
193         float maxFormSize = 0f;
194         float formToTextSpace = Utils.convertDpToPixel(mFormToTextSpace);
195 
196         for (LegendEntry entry : mEntries) {
197             final float formSize = Utils.convertDpToPixel(
198                     Float.isNaN(entry.formSize)
199                     ? mFormSize : entry.formSize);
200             if (formSize > maxFormSize)
201                 maxFormSize = formSize;
202 
203             String label = entry.label;
204             if (label == null) continue;
205 
206             float length = (float) Utils.calcTextWidth(p, label);
207 
208             if (length > max)
209                 max = length;
210         }
211 
212         return max + maxFormSize + formToTextSpace;
213     }
214 
215     /**
216      * returns the maximum height in pixels across all legend labels
217      *
218      * @param p the paint object used for rendering the text
219      * @return
220      */
getMaximumEntryHeight(Paint p)221     public float getMaximumEntryHeight(Paint p) {
222 
223         float max = 0f;
224 
225         for (LegendEntry entry : mEntries) {
226             String label = entry.label;
227             if (label == null) continue;
228 
229             float length = (float) Utils.calcTextHeight(p, label);
230 
231             if (length > max)
232                 max = length;
233         }
234 
235         return max;
236     }
237 
getExtraEntries()238     public LegendEntry[] getExtraEntries() {
239 
240         return mExtraEntries;
241     }
242 
setExtra(List<LegendEntry> entries)243     public void setExtra(List<LegendEntry> entries) {
244         mExtraEntries = entries.toArray(new LegendEntry[entries.size()]);
245     }
246 
setExtra(LegendEntry[] entries)247     public void setExtra(LegendEntry[] entries) {
248         if (entries == null)
249             entries = new LegendEntry[]{};
250         mExtraEntries = entries;
251     }
252 
253     /**
254      * Entries that will be appended to the end of the auto calculated
255      *   entries after calculating the legend.
256      * (if the legend has already been calculated, you will need to call notifyDataSetChanged()
257      *   to let the changes take effect)
258      */
setExtra(int[] colors, String[] labels)259     public void setExtra(int[] colors, String[] labels) {
260 
261         List<LegendEntry> entries = new ArrayList<>();
262 
263         for (int i = 0; i < Math.min(colors.length, labels.length); i++) {
264             final LegendEntry entry = new LegendEntry();
265             entry.formColor = colors[i];
266             entry.label = labels[i];
267 
268             if (entry.formColor == ColorTemplate.COLOR_SKIP ||
269                     entry.formColor == 0)
270                 entry.form = LegendForm.NONE;
271             else if (entry.formColor == ColorTemplate.COLOR_NONE)
272                 entry.form = LegendForm.EMPTY;
273 
274             entries.add(entry);
275         }
276 
277         mExtraEntries = entries.toArray(new LegendEntry[entries.size()]);
278     }
279 
280     /**
281      * Sets a custom legend's entries array.
282      * * A null label will start a group.
283      * This will disable the feature that automatically calculates the legend
284      *   entries from the datasets.
285      * Call resetCustom() to re-enable automatic calculation (and then
286      *   notifyDataSetChanged() is needed to auto-calculate the legend again)
287      */
setCustom(LegendEntry[] entries)288     public void setCustom(LegendEntry[] entries) {
289 
290         mEntries = entries;
291         mIsLegendCustom = true;
292     }
293 
294     /**
295      * Sets a custom legend's entries array.
296      * * A null label will start a group.
297      * This will disable the feature that automatically calculates the legend
298      *   entries from the datasets.
299      * Call resetCustom() to re-enable automatic calculation (and then
300      *   notifyDataSetChanged() is needed to auto-calculate the legend again)
301      */
setCustom(List<LegendEntry> entries)302     public void setCustom(List<LegendEntry> entries) {
303 
304         mEntries = entries.toArray(new LegendEntry[entries.size()]);
305         mIsLegendCustom = true;
306     }
307 
308     /**
309      * Calling this will disable the custom legend entries (set by
310      * setCustom(...)). Instead, the entries will again be calculated
311      * automatically (after notifyDataSetChanged() is called).
312      */
resetCustom()313     public void resetCustom() {
314         mIsLegendCustom = false;
315     }
316 
317     /**
318      * @return true if a custom legend entries has been set default
319      * false (automatic legend)
320      */
isLegendCustom()321     public boolean isLegendCustom() {
322         return mIsLegendCustom;
323     }
324 
325     /**
326      * returns the horizontal alignment of the legend
327      *
328      * @return
329      */
getHorizontalAlignment()330     public LegendHorizontalAlignment getHorizontalAlignment() {
331         return mHorizontalAlignment;
332     }
333 
334     /**
335      * sets the horizontal alignment of the legend
336      *
337      * @param value
338      */
setHorizontalAlignment(LegendHorizontalAlignment value)339     public void setHorizontalAlignment(LegendHorizontalAlignment value) {
340         mHorizontalAlignment = value;
341     }
342 
343     /**
344      * returns the vertical alignment of the legend
345      *
346      * @return
347      */
getVerticalAlignment()348     public LegendVerticalAlignment getVerticalAlignment() {
349         return mVerticalAlignment;
350     }
351 
352     /**
353      * sets the vertical alignment of the legend
354      *
355      * @param value
356      */
setVerticalAlignment(LegendVerticalAlignment value)357     public void setVerticalAlignment(LegendVerticalAlignment value) {
358         mVerticalAlignment = value;
359     }
360 
361     /**
362      * returns the orientation of the legend
363      *
364      * @return
365      */
getOrientation()366     public LegendOrientation getOrientation() {
367         return mOrientation;
368     }
369 
370     /**
371      * sets the orientation of the legend
372      *
373      * @param value
374      */
setOrientation(LegendOrientation value)375     public void setOrientation(LegendOrientation value) {
376         mOrientation = value;
377     }
378 
379     /**
380      * returns whether the legend will draw inside the chart or outside
381      *
382      * @return
383      */
isDrawInsideEnabled()384     public boolean isDrawInsideEnabled() {
385         return mDrawInside;
386     }
387 
388     /**
389      * sets whether the legend will draw inside the chart or outside
390      *
391      * @param value
392      */
setDrawInside(boolean value)393     public void setDrawInside(boolean value) {
394         mDrawInside = value;
395     }
396 
397     /**
398      * returns the text direction of the legend
399      *
400      * @return
401      */
getDirection()402     public LegendDirection getDirection() {
403         return mDirection;
404     }
405 
406     /**
407      * sets the text direction of the legend
408      *
409      * @param pos
410      */
setDirection(LegendDirection pos)411     public void setDirection(LegendDirection pos) {
412         mDirection = pos;
413     }
414 
415     /**
416      * returns the current form/shape that is set for the legend
417      *
418      * @return
419      */
getForm()420     public LegendForm getForm() {
421         return mShape;
422     }
423 
424     /**
425      * sets the form/shape of the legend forms
426      *
427      * @param shape
428      */
setForm(LegendForm shape)429     public void setForm(LegendForm shape) {
430         mShape = shape;
431     }
432 
433     /**
434      * sets the size in dp of the legend forms, default 8f
435      *
436      * @param size
437      */
setFormSize(float size)438     public void setFormSize(float size) {
439         mFormSize = size;
440     }
441 
442     /**
443      * returns the size in dp of the legend forms
444      *
445      * @return
446      */
getFormSize()447     public float getFormSize() {
448         return mFormSize;
449     }
450 
451     /**
452      * sets the line width in dp for forms that consist of lines, default 3f
453      *
454      * @param size
455      */
setFormLineWidth(float size)456     public void setFormLineWidth(float size) {
457         mFormLineWidth = size;
458     }
459 
460     /**
461      * returns the line width in dp for drawing forms that consist of lines
462      *
463      * @return
464      */
getFormLineWidth()465     public float getFormLineWidth() {
466         return mFormLineWidth;
467     }
468 
469     /**
470      * Sets the line dash path effect used for shapes that consist of lines.
471      *
472      * @param dashPathEffect
473      */
setFormLineDashEffect(DashPathEffect dashPathEffect)474     public void setFormLineDashEffect(DashPathEffect dashPathEffect) {
475         mFormLineDashEffect = dashPathEffect;
476     }
477 
478     /**
479      * @return The line dash path effect used for shapes that consist of lines.
480      */
getFormLineDashEffect()481     public DashPathEffect getFormLineDashEffect() {
482         return mFormLineDashEffect;
483     }
484 
485     /**
486      * returns the space between the legend entries on a horizontal axis in
487      * pixels
488      *
489      * @return
490      */
getXEntrySpace()491     public float getXEntrySpace() {
492         return mXEntrySpace;
493     }
494 
495     /**
496      * sets the space between the legend entries on a horizontal axis in pixels,
497      * converts to dp internally
498      *
499      * @param space
500      */
setXEntrySpace(float space)501     public void setXEntrySpace(float space) {
502         mXEntrySpace = space;
503     }
504 
505     /**
506      * returns the space between the legend entries on a vertical axis in pixels
507      *
508      * @return
509      */
getYEntrySpace()510     public float getYEntrySpace() {
511         return mYEntrySpace;
512     }
513 
514     /**
515      * sets the space between the legend entries on a vertical axis in pixels,
516      * converts to dp internally
517      *
518      * @param space
519      */
setYEntrySpace(float space)520     public void setYEntrySpace(float space) {
521         mYEntrySpace = space;
522     }
523 
524     /**
525      * returns the space between the form and the actual label/text
526      *
527      * @return
528      */
getFormToTextSpace()529     public float getFormToTextSpace() {
530         return mFormToTextSpace;
531     }
532 
533     /**
534      * sets the space between the form and the actual label/text, converts to dp
535      * internally
536      *
537      * @param space
538      */
setFormToTextSpace(float space)539     public void setFormToTextSpace(float space) {
540         this.mFormToTextSpace = space;
541     }
542 
543     /**
544      * returns the space that is left out between stacked forms (with no label)
545      *
546      * @return
547      */
getStackSpace()548     public float getStackSpace() {
549         return mStackSpace;
550     }
551 
552     /**
553      * sets the space that is left out between stacked forms (with no label)
554      *
555      * @param space
556      */
setStackSpace(float space)557     public void setStackSpace(float space) {
558         mStackSpace = space;
559     }
560 
561     /**
562      * the total width of the legend (needed width space)
563      */
564     public float mNeededWidth = 0f;
565 
566     /**
567      * the total height of the legend (needed height space)
568      */
569     public float mNeededHeight = 0f;
570 
571     public float mTextHeightMax = 0f;
572 
573     public float mTextWidthMax = 0f;
574 
575     /**
576      * flag that indicates if word wrapping is enabled
577      */
578     private boolean mWordWrapEnabled = false;
579 
580     /**
581      * Should the legend word wrap? / this is currently supported only for:
582      * BelowChartLeft, BelowChartRight, BelowChartCenter. / note that word
583      * wrapping a legend takes a toll on performance. / you may want to set
584      * maxSizePercent when word wrapping, to set the point where the text wraps.
585      * / default: false
586      *
587      * @param enabled
588      */
setWordWrapEnabled(boolean enabled)589     public void setWordWrapEnabled(boolean enabled) {
590         mWordWrapEnabled = enabled;
591     }
592 
593     /**
594      * If this is set, then word wrapping the legend is enabled. This means the
595      * legend will not be cut off if too long.
596      *
597      * @return
598      */
isWordWrapEnabled()599     public boolean isWordWrapEnabled() {
600         return mWordWrapEnabled;
601     }
602 
603     /**
604      * The maximum relative size out of the whole chart view. / If the legend is
605      * to the right/left of the chart, then this affects the width of the
606      * legend. / If the legend is to the top/bottom of the chart, then this
607      * affects the height of the legend. / If the legend is the center of the
608      * piechart, then this defines the size of the rectangular bounds out of the
609      * size of the "hole". / default: 0.95f (95%)
610      *
611      * @return
612      */
getMaxSizePercent()613     public float getMaxSizePercent() {
614         return mMaxSizePercent;
615     }
616 
617     /**
618      * The maximum relative size out of the whole chart view. / If
619      * the legend is to the right/left of the chart, then this affects the width
620      * of the legend. / If the legend is to the top/bottom of the chart, then
621      * this affects the height of the legend. / default: 0.95f (95%)
622      *
623      * @param maxSize
624      */
setMaxSizePercent(float maxSize)625     public void setMaxSizePercent(float maxSize) {
626         mMaxSizePercent = maxSize;
627     }
628 
629     private List<FSize> mCalculatedLabelSizes = new ArrayList<>(16);
630     private List<Boolean> mCalculatedLabelBreakPoints = new ArrayList<>(16);
631     private List<FSize> mCalculatedLineSizes = new ArrayList<>(16);
632 
getCalculatedLabelSizes()633     public List<FSize> getCalculatedLabelSizes() {
634         return mCalculatedLabelSizes;
635     }
636 
getCalculatedLabelBreakPoints()637     public List<Boolean> getCalculatedLabelBreakPoints() {
638         return mCalculatedLabelBreakPoints;
639     }
640 
getCalculatedLineSizes()641     public List<FSize> getCalculatedLineSizes() {
642         return mCalculatedLineSizes;
643     }
644 
645     /**
646      * Calculates the dimensions of the Legend. This includes the maximum width
647      * and height of a single entry, as well as the total width and height of
648      * the Legend.
649      *
650      * @param labelpaint
651      */
calculateDimensions(Paint labelpaint, ViewPortHandler viewPortHandler)652     public void calculateDimensions(Paint labelpaint, ViewPortHandler viewPortHandler) {
653 
654         float defaultFormSize = Utils.convertDpToPixel(mFormSize);
655         float stackSpace = Utils.convertDpToPixel(mStackSpace);
656         float formToTextSpace = Utils.convertDpToPixel(mFormToTextSpace);
657         float xEntrySpace = Utils.convertDpToPixel(mXEntrySpace);
658         float yEntrySpace = Utils.convertDpToPixel(mYEntrySpace);
659         boolean wordWrapEnabled = mWordWrapEnabled;
660         LegendEntry[] entries = mEntries;
661         int entryCount = entries.length;
662 
663         mTextWidthMax = getMaximumEntryWidth(labelpaint);
664         mTextHeightMax = getMaximumEntryHeight(labelpaint);
665 
666         switch (mOrientation) {
667             case VERTICAL: {
668 
669                 float maxWidth = 0f, maxHeight = 0f, width = 0f;
670                 float labelLineHeight = Utils.getLineHeight(labelpaint);
671                 boolean wasStacked = false;
672 
673                 for (int i = 0; i < entryCount; i++) {
674 
675                     LegendEntry e = entries[i];
676                     boolean drawingForm = e.form != LegendForm.NONE;
677                     float formSize = Float.isNaN(e.formSize)
678                             ? defaultFormSize
679                             : Utils.convertDpToPixel(e.formSize);
680                     String label = e.label;
681 
682                     if (!wasStacked)
683                         width = 0.f;
684 
685                     if (drawingForm) {
686                         if (wasStacked)
687                             width += stackSpace;
688                         width += formSize;
689                     }
690 
691                     // grouped forms have null labels
692                     if (label != null) {
693 
694                         // make a step to the left
695                         if (drawingForm && !wasStacked)
696                             width += formToTextSpace;
697                         else if (wasStacked) {
698                             maxWidth = Math.max(maxWidth, width);
699                             maxHeight += labelLineHeight + yEntrySpace;
700                             width = 0.f;
701                             wasStacked = false;
702                         }
703 
704                         width += Utils.calcTextWidth(labelpaint, label);
705 
706                         maxHeight += labelLineHeight + yEntrySpace;
707                     } else {
708                         wasStacked = true;
709                         width += formSize;
710                         if (i < entryCount - 1)
711                             width += stackSpace;
712                     }
713 
714                     maxWidth = Math.max(maxWidth, width);
715                 }
716 
717                 mNeededWidth = maxWidth;
718                 mNeededHeight = maxHeight;
719 
720                 break;
721             }
722             case HORIZONTAL: {
723 
724                 float labelLineHeight = Utils.getLineHeight(labelpaint);
725                 float labelLineSpacing = Utils.getLineSpacing(labelpaint) + yEntrySpace;
726                 float contentWidth = viewPortHandler.contentWidth() * mMaxSizePercent;
727 
728                 // Start calculating layout
729                 float maxLineWidth = 0.f;
730                 float currentLineWidth = 0.f;
731                 float requiredWidth = 0.f;
732                 int stackedStartIndex = -1;
733 
734                 mCalculatedLabelBreakPoints.clear();
735                 mCalculatedLabelSizes.clear();
736                 mCalculatedLineSizes.clear();
737 
738                 for (int i = 0; i < entryCount; i++) {
739 
740                     LegendEntry e = entries[i];
741                     boolean drawingForm = e.form != LegendForm.NONE;
742                     float formSize = Float.isNaN(e.formSize)
743                             ? defaultFormSize
744                             : Utils.convertDpToPixel(e.formSize);
745                     String label = e.label;
746 
747                     mCalculatedLabelBreakPoints.add(false);
748 
749                     if (stackedStartIndex == -1) {
750                         // we are not stacking, so required width is for this label
751                         // only
752                         requiredWidth = 0.f;
753                     } else {
754                         // add the spacing appropriate for stacked labels/forms
755                         requiredWidth += stackSpace;
756                     }
757 
758                     // grouped forms have null labels
759                     if (label != null) {
760 
761                         mCalculatedLabelSizes.add(Utils.calcTextSize(labelpaint, label));
762                         requiredWidth += drawingForm ? formToTextSpace + formSize : 0.f;
763                         requiredWidth += mCalculatedLabelSizes.get(i).width;
764                     } else {
765 
766                         mCalculatedLabelSizes.add(FSize.getInstance(0.f, 0.f));
767                         requiredWidth += drawingForm ? formSize : 0.f;
768 
769                         if (stackedStartIndex == -1) {
770                             // mark this index as we might want to break here later
771                             stackedStartIndex = i;
772                         }
773                     }
774 
775                     if (label != null || i == entryCount - 1) {
776 
777                         float requiredSpacing = currentLineWidth == 0.f ? 0.f : xEntrySpace;
778 
779                         if (!wordWrapEnabled // No word wrapping, it must fit.
780                                 // The line is empty, it must fit
781                                 || currentLineWidth == 0.f
782                                 // It simply fits
783                                 || (contentWidth - currentLineWidth >=
784                                 requiredSpacing + requiredWidth)) {
785                             // Expand current line
786                             currentLineWidth += requiredSpacing + requiredWidth;
787                         } else { // It doesn't fit, we need to wrap a line
788 
789                             // Add current line size to array
790                             mCalculatedLineSizes.add(FSize.getInstance(currentLineWidth, labelLineHeight));
791                             maxLineWidth = Math.max(maxLineWidth, currentLineWidth);
792 
793                             // Start a new line
794                             mCalculatedLabelBreakPoints.set(
795                                     stackedStartIndex > -1 ? stackedStartIndex
796                                             : i, true);
797                             currentLineWidth = requiredWidth;
798                         }
799 
800                         if (i == entryCount - 1) {
801                             // Add last line size to array
802                             mCalculatedLineSizes.add(FSize.getInstance(currentLineWidth, labelLineHeight));
803                             maxLineWidth = Math.max(maxLineWidth, currentLineWidth);
804                         }
805                     }
806 
807                     stackedStartIndex = label != null ? -1 : stackedStartIndex;
808                 }
809 
810                 mNeededWidth = maxLineWidth;
811                 mNeededHeight = labelLineHeight
812                         * (float) (mCalculatedLineSizes.size())
813                         + labelLineSpacing *
814                         (float) (mCalculatedLineSizes.size() == 0
815                                 ? 0
816                                 : (mCalculatedLineSizes.size() - 1));
817 
818                 break;
819             }
820         }
821 
822         mNeededHeight += mYOffset;
823         mNeededWidth += mXOffset;
824     }
825 }
826