• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.widget;
18 
19 import com.android.internal.R;
20 
21 import android.content.Context;
22 import android.content.res.TypedArray;
23 import android.graphics.Canvas;
24 import android.graphics.drawable.Drawable;
25 import android.util.AttributeSet;
26 import android.view.Gravity;
27 import android.view.View;
28 import android.view.ViewDebug;
29 import android.view.ViewGroup;
30 import android.view.accessibility.AccessibilityEvent;
31 import android.view.accessibility.AccessibilityNodeInfo;
32 import android.widget.RemoteViews.RemoteView;
33 
34 
35 /**
36  * A Layout that arranges its children in a single column or a single row. The direction of
37  * the row can be set by calling {@link #setOrientation(int) setOrientation()}.
38  * You can also specify gravity, which specifies the alignment of all the child elements by
39  * calling {@link #setGravity(int) setGravity()} or specify that specific children
40  * grow to fill up any remaining space in the layout by setting the <em>weight</em> member of
41  * {@link android.widget.LinearLayout.LayoutParams LinearLayout.LayoutParams}.
42  * The default orientation is horizontal.
43  *
44  * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-linearlayout.html">Linear Layout
45  * tutorial</a>.</p>
46  *
47  * <p>
48  * Also see {@link LinearLayout.LayoutParams android.widget.LinearLayout.LayoutParams}
49  * for layout attributes </p>
50  *
51  * @attr ref android.R.styleable#LinearLayout_baselineAligned
52  * @attr ref android.R.styleable#LinearLayout_baselineAlignedChildIndex
53  * @attr ref android.R.styleable#LinearLayout_gravity
54  * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
55  * @attr ref android.R.styleable#LinearLayout_orientation
56  * @attr ref android.R.styleable#LinearLayout_weightSum
57  */
58 @RemoteView
59 public class LinearLayout extends ViewGroup {
60     public static final int HORIZONTAL = 0;
61     public static final int VERTICAL = 1;
62 
63     /**
64      * Don't show any dividers.
65      */
66     public static final int SHOW_DIVIDER_NONE = 0;
67     /**
68      * Show a divider at the beginning of the group.
69      */
70     public static final int SHOW_DIVIDER_BEGINNING = 1;
71     /**
72      * Show dividers between each item in the group.
73      */
74     public static final int SHOW_DIVIDER_MIDDLE = 2;
75     /**
76      * Show a divider at the end of the group.
77      */
78     public static final int SHOW_DIVIDER_END = 4;
79 
80     /**
81      * Whether the children of this layout are baseline aligned.  Only applicable
82      * if {@link #mOrientation} is horizontal.
83      */
84     @ViewDebug.ExportedProperty(category = "layout")
85     private boolean mBaselineAligned = true;
86 
87     /**
88      * If this layout is part of another layout that is baseline aligned,
89      * use the child at this index as the baseline.
90      *
91      * Note: this is orthogonal to {@link #mBaselineAligned}, which is concerned
92      * with whether the children of this layout are baseline aligned.
93      */
94     @ViewDebug.ExportedProperty(category = "layout")
95     private int mBaselineAlignedChildIndex = -1;
96 
97     /**
98      * The additional offset to the child's baseline.
99      * We'll calculate the baseline of this layout as we measure vertically; for
100      * horizontal linear layouts, the offset of 0 is appropriate.
101      */
102     @ViewDebug.ExportedProperty(category = "measurement")
103     private int mBaselineChildTop = 0;
104 
105     @ViewDebug.ExportedProperty(category = "measurement")
106     private int mOrientation;
107 
108     @ViewDebug.ExportedProperty(category = "measurement", flagMapping = {
109             @ViewDebug.FlagToString(mask = -1,
110                 equals = -1, name = "NONE"),
111             @ViewDebug.FlagToString(mask = Gravity.NO_GRAVITY,
112                 equals = Gravity.NO_GRAVITY,name = "NONE"),
113             @ViewDebug.FlagToString(mask = Gravity.TOP,
114                 equals = Gravity.TOP, name = "TOP"),
115             @ViewDebug.FlagToString(mask = Gravity.BOTTOM,
116                 equals = Gravity.BOTTOM, name = "BOTTOM"),
117             @ViewDebug.FlagToString(mask = Gravity.LEFT,
118                 equals = Gravity.LEFT, name = "LEFT"),
119             @ViewDebug.FlagToString(mask = Gravity.RIGHT,
120                 equals = Gravity.RIGHT, name = "RIGHT"),
121             @ViewDebug.FlagToString(mask = Gravity.START,
122                 equals = Gravity.START, name = "START"),
123             @ViewDebug.FlagToString(mask = Gravity.END,
124                 equals = Gravity.END, name = "END"),
125             @ViewDebug.FlagToString(mask = Gravity.CENTER_VERTICAL,
126                 equals = Gravity.CENTER_VERTICAL, name = "CENTER_VERTICAL"),
127             @ViewDebug.FlagToString(mask = Gravity.FILL_VERTICAL,
128                 equals = Gravity.FILL_VERTICAL, name = "FILL_VERTICAL"),
129             @ViewDebug.FlagToString(mask = Gravity.CENTER_HORIZONTAL,
130                 equals = Gravity.CENTER_HORIZONTAL, name = "CENTER_HORIZONTAL"),
131             @ViewDebug.FlagToString(mask = Gravity.FILL_HORIZONTAL,
132                 equals = Gravity.FILL_HORIZONTAL, name = "FILL_HORIZONTAL"),
133             @ViewDebug.FlagToString(mask = Gravity.CENTER,
134                 equals = Gravity.CENTER, name = "CENTER"),
135             @ViewDebug.FlagToString(mask = Gravity.FILL,
136                 equals = Gravity.FILL, name = "FILL"),
137             @ViewDebug.FlagToString(mask = Gravity.RELATIVE_LAYOUT_DIRECTION,
138                 equals = Gravity.RELATIVE_LAYOUT_DIRECTION, name = "RELATIVE")
139         })
140     private int mGravity = Gravity.START | Gravity.TOP;
141 
142     @ViewDebug.ExportedProperty(category = "measurement")
143     private int mTotalLength;
144 
145     @ViewDebug.ExportedProperty(category = "layout")
146     private float mWeightSum;
147 
148     @ViewDebug.ExportedProperty(category = "layout")
149     private boolean mUseLargestChild;
150 
151     private int[] mMaxAscent;
152     private int[] mMaxDescent;
153 
154     private static final int VERTICAL_GRAVITY_COUNT = 4;
155 
156     private static final int INDEX_CENTER_VERTICAL = 0;
157     private static final int INDEX_TOP = 1;
158     private static final int INDEX_BOTTOM = 2;
159     private static final int INDEX_FILL = 3;
160 
161     private Drawable mDivider;
162     private int mDividerWidth;
163     private int mDividerHeight;
164     private int mShowDividers;
165     private int mDividerPadding;
166 
LinearLayout(Context context)167     public LinearLayout(Context context) {
168         super(context);
169     }
170 
LinearLayout(Context context, AttributeSet attrs)171     public LinearLayout(Context context, AttributeSet attrs) {
172         this(context, attrs, 0);
173     }
174 
LinearLayout(Context context, AttributeSet attrs, int defStyle)175     public LinearLayout(Context context, AttributeSet attrs, int defStyle) {
176         super(context, attrs, defStyle);
177 
178         TypedArray a = context.obtainStyledAttributes(attrs,
179                 com.android.internal.R.styleable.LinearLayout, defStyle, 0);
180 
181         int index = a.getInt(com.android.internal.R.styleable.LinearLayout_orientation, -1);
182         if (index >= 0) {
183             setOrientation(index);
184         }
185 
186         index = a.getInt(com.android.internal.R.styleable.LinearLayout_gravity, -1);
187         if (index >= 0) {
188             setGravity(index);
189         }
190 
191         boolean baselineAligned = a.getBoolean(R.styleable.LinearLayout_baselineAligned, true);
192         if (!baselineAligned) {
193             setBaselineAligned(baselineAligned);
194         }
195 
196         mWeightSum = a.getFloat(R.styleable.LinearLayout_weightSum, -1.0f);
197 
198         mBaselineAlignedChildIndex =
199                 a.getInt(com.android.internal.R.styleable.LinearLayout_baselineAlignedChildIndex, -1);
200 
201         mUseLargestChild = a.getBoolean(R.styleable.LinearLayout_measureWithLargestChild, false);
202 
203         setDividerDrawable(a.getDrawable(R.styleable.LinearLayout_divider));
204         mShowDividers = a.getInt(R.styleable.LinearLayout_showDividers, SHOW_DIVIDER_NONE);
205         mDividerPadding = a.getDimensionPixelSize(R.styleable.LinearLayout_dividerPadding, 0);
206 
207         a.recycle();
208     }
209 
210     /**
211      * Set how dividers should be shown between items in this layout
212      *
213      * @param showDividers One or more of {@link #SHOW_DIVIDER_BEGINNING},
214      *                     {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END},
215      *                     or {@link #SHOW_DIVIDER_NONE} to show no dividers.
216      */
setShowDividers(int showDividers)217     public void setShowDividers(int showDividers) {
218         if (showDividers != mShowDividers) {
219             requestLayout();
220         }
221         mShowDividers = showDividers;
222     }
223 
224     @Override
shouldDelayChildPressedState()225     public boolean shouldDelayChildPressedState() {
226         return false;
227     }
228 
229     /**
230      * @return A flag set indicating how dividers should be shown around items.
231      * @see #setShowDividers(int)
232      */
getShowDividers()233     public int getShowDividers() {
234         return mShowDividers;
235     }
236 
237     /**
238      * @return the divider Drawable that will divide each item.
239      *
240      * @see #setDividerDrawable(Drawable)
241      *
242      * @attr ref android.R.styleable#LinearLayout_divider
243      */
getDividerDrawable()244     public Drawable getDividerDrawable() {
245         return mDivider;
246     }
247 
248     /**
249      * Set a drawable to be used as a divider between items.
250      *
251      * @param divider Drawable that will divide each item.
252      *
253      * @see #setShowDividers(int)
254      *
255      * @attr ref android.R.styleable#LinearLayout_divider
256      */
setDividerDrawable(Drawable divider)257     public void setDividerDrawable(Drawable divider) {
258         if (divider == mDivider) {
259             return;
260         }
261         mDivider = divider;
262         if (divider != null) {
263             mDividerWidth = divider.getIntrinsicWidth();
264             mDividerHeight = divider.getIntrinsicHeight();
265         } else {
266             mDividerWidth = 0;
267             mDividerHeight = 0;
268         }
269         setWillNotDraw(divider == null);
270         requestLayout();
271     }
272 
273     /**
274      * Set padding displayed on both ends of dividers.
275      *
276      * @param padding Padding value in pixels that will be applied to each end
277      *
278      * @see #setShowDividers(int)
279      * @see #setDividerDrawable(Drawable)
280      * @see #getDividerPadding()
281      */
setDividerPadding(int padding)282     public void setDividerPadding(int padding) {
283         mDividerPadding = padding;
284     }
285 
286     /**
287      * Get the padding size used to inset dividers in pixels
288      *
289      * @see #setShowDividers(int)
290      * @see #setDividerDrawable(Drawable)
291      * @see #setDividerPadding(int)
292      */
getDividerPadding()293     public int getDividerPadding() {
294         return mDividerPadding;
295     }
296 
297     /**
298      * Get the width of the current divider drawable.
299      *
300      * @hide Used internally by framework.
301      */
getDividerWidth()302     public int getDividerWidth() {
303         return mDividerWidth;
304     }
305 
306     @Override
onDraw(Canvas canvas)307     protected void onDraw(Canvas canvas) {
308         if (mDivider == null) {
309             return;
310         }
311 
312         if (mOrientation == VERTICAL) {
313             drawDividersVertical(canvas);
314         } else {
315             drawDividersHorizontal(canvas);
316         }
317     }
318 
drawDividersVertical(Canvas canvas)319     void drawDividersVertical(Canvas canvas) {
320         final int count = getVirtualChildCount();
321         for (int i = 0; i < count; i++) {
322             final View child = getVirtualChildAt(i);
323 
324             if (child != null && child.getVisibility() != GONE) {
325                 if (hasDividerBeforeChildAt(i)) {
326                     final LayoutParams lp = (LayoutParams) child.getLayoutParams();
327                     final int top = child.getTop() - lp.topMargin - mDividerHeight;
328                     drawHorizontalDivider(canvas, top);
329                 }
330             }
331         }
332 
333         if (hasDividerBeforeChildAt(count)) {
334             final View child = getVirtualChildAt(count - 1);
335             int bottom = 0;
336             if (child == null) {
337                 bottom = getHeight() - getPaddingBottom() - mDividerHeight;
338             } else {
339                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
340                 bottom = child.getBottom() + lp.bottomMargin;
341             }
342             drawHorizontalDivider(canvas, bottom);
343         }
344     }
345 
drawDividersHorizontal(Canvas canvas)346     void drawDividersHorizontal(Canvas canvas) {
347         final int count = getVirtualChildCount();
348         for (int i = 0; i < count; i++) {
349             final View child = getVirtualChildAt(i);
350 
351             if (child != null && child.getVisibility() != GONE) {
352                 if (hasDividerBeforeChildAt(i)) {
353                     final LayoutParams lp = (LayoutParams) child.getLayoutParams();
354                     final int left = child.getLeft() - lp.leftMargin - mDividerWidth;
355                     drawVerticalDivider(canvas, left);
356                 }
357             }
358         }
359 
360         if (hasDividerBeforeChildAt(count)) {
361             final View child = getVirtualChildAt(count - 1);
362             int right = 0;
363             if (child == null) {
364                 right = getWidth() - getPaddingRight() - mDividerWidth;
365             } else {
366                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
367                 right = child.getRight() + lp.rightMargin;
368             }
369             drawVerticalDivider(canvas, right);
370         }
371     }
372 
drawHorizontalDivider(Canvas canvas, int top)373     void drawHorizontalDivider(Canvas canvas, int top) {
374         mDivider.setBounds(getPaddingLeft() + mDividerPadding, top,
375                 getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);
376         mDivider.draw(canvas);
377     }
378 
drawVerticalDivider(Canvas canvas, int left)379     void drawVerticalDivider(Canvas canvas, int left) {
380         mDivider.setBounds(left, getPaddingTop() + mDividerPadding,
381                 left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding);
382         mDivider.draw(canvas);
383     }
384 
385     /**
386      * <p>Indicates whether widgets contained within this layout are aligned
387      * on their baseline or not.</p>
388      *
389      * @return true when widgets are baseline-aligned, false otherwise
390      */
isBaselineAligned()391     public boolean isBaselineAligned() {
392         return mBaselineAligned;
393     }
394 
395     /**
396      * <p>Defines whether widgets contained in this layout are
397      * baseline-aligned or not.</p>
398      *
399      * @param baselineAligned true to align widgets on their baseline,
400      *         false otherwise
401      *
402      * @attr ref android.R.styleable#LinearLayout_baselineAligned
403      */
404     @android.view.RemotableViewMethod
setBaselineAligned(boolean baselineAligned)405     public void setBaselineAligned(boolean baselineAligned) {
406         mBaselineAligned = baselineAligned;
407     }
408 
409     /**
410      * When true, all children with a weight will be considered having
411      * the minimum size of the largest child. If false, all children are
412      * measured normally.
413      *
414      * @return True to measure children with a weight using the minimum
415      *         size of the largest child, false otherwise.
416      *
417      * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
418      */
isMeasureWithLargestChildEnabled()419     public boolean isMeasureWithLargestChildEnabled() {
420         return mUseLargestChild;
421     }
422 
423     /**
424      * When set to true, all children with a weight will be considered having
425      * the minimum size of the largest child. If false, all children are
426      * measured normally.
427      *
428      * Disabled by default.
429      *
430      * @param enabled True to measure children with a weight using the
431      *        minimum size of the largest child, false otherwise.
432      *
433      * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
434      */
435     @android.view.RemotableViewMethod
setMeasureWithLargestChildEnabled(boolean enabled)436     public void setMeasureWithLargestChildEnabled(boolean enabled) {
437         mUseLargestChild = enabled;
438     }
439 
440     @Override
getBaseline()441     public int getBaseline() {
442         if (mBaselineAlignedChildIndex < 0) {
443             return super.getBaseline();
444         }
445 
446         if (getChildCount() <= mBaselineAlignedChildIndex) {
447             throw new RuntimeException("mBaselineAlignedChildIndex of LinearLayout "
448                     + "set to an index that is out of bounds.");
449         }
450 
451         final View child = getChildAt(mBaselineAlignedChildIndex);
452         final int childBaseline = child.getBaseline();
453 
454         if (childBaseline == -1) {
455             if (mBaselineAlignedChildIndex == 0) {
456                 // this is just the default case, safe to return -1
457                 return -1;
458             }
459             // the user picked an index that points to something that doesn't
460             // know how to calculate its baseline.
461             throw new RuntimeException("mBaselineAlignedChildIndex of LinearLayout "
462                     + "points to a View that doesn't know how to get its baseline.");
463         }
464 
465         // TODO: This should try to take into account the virtual offsets
466         // (See getNextLocationOffset and getLocationOffset)
467         // We should add to childTop:
468         // sum([getNextLocationOffset(getChildAt(i)) / i < mBaselineAlignedChildIndex])
469         // and also add:
470         // getLocationOffset(child)
471         int childTop = mBaselineChildTop;
472 
473         if (mOrientation == VERTICAL) {
474             final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
475             if (majorGravity != Gravity.TOP) {
476                switch (majorGravity) {
477                    case Gravity.BOTTOM:
478                        childTop = mBottom - mTop - mPaddingBottom - mTotalLength;
479                        break;
480 
481                    case Gravity.CENTER_VERTICAL:
482                        childTop += ((mBottom - mTop - mPaddingTop - mPaddingBottom) -
483                                mTotalLength) / 2;
484                        break;
485                }
486             }
487         }
488 
489         LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
490         return childTop + lp.topMargin + childBaseline;
491     }
492 
493     /**
494      * @return The index of the child that will be used if this layout is
495      *   part of a larger layout that is baseline aligned, or -1 if none has
496      *   been set.
497      */
getBaselineAlignedChildIndex()498     public int getBaselineAlignedChildIndex() {
499         return mBaselineAlignedChildIndex;
500     }
501 
502     /**
503      * @param i The index of the child that will be used if this layout is
504      *          part of a larger layout that is baseline aligned.
505      *
506      * @attr ref android.R.styleable#LinearLayout_baselineAlignedChildIndex
507      */
508     @android.view.RemotableViewMethod
setBaselineAlignedChildIndex(int i)509     public void setBaselineAlignedChildIndex(int i) {
510         if ((i < 0) || (i >= getChildCount())) {
511             throw new IllegalArgumentException("base aligned child index out "
512                     + "of range (0, " + getChildCount() + ")");
513         }
514         mBaselineAlignedChildIndex = i;
515     }
516 
517     /**
518      * <p>Returns the view at the specified index. This method can be overriden
519      * to take into account virtual children. Refer to
520      * {@link android.widget.TableLayout} and {@link android.widget.TableRow}
521      * for an example.</p>
522      *
523      * @param index the child's index
524      * @return the child at the specified index
525      */
getVirtualChildAt(int index)526     View getVirtualChildAt(int index) {
527         return getChildAt(index);
528     }
529 
530     /**
531      * <p>Returns the virtual number of children. This number might be different
532      * than the actual number of children if the layout can hold virtual
533      * children. Refer to
534      * {@link android.widget.TableLayout} and {@link android.widget.TableRow}
535      * for an example.</p>
536      *
537      * @return the virtual number of children
538      */
getVirtualChildCount()539     int getVirtualChildCount() {
540         return getChildCount();
541     }
542 
543     /**
544      * Returns the desired weights sum.
545      *
546      * @return A number greater than 0.0f if the weight sum is defined, or
547      *         a number lower than or equals to 0.0f if not weight sum is
548      *         to be used.
549      */
getWeightSum()550     public float getWeightSum() {
551         return mWeightSum;
552     }
553 
554     /**
555      * Defines the desired weights sum. If unspecified the weights sum is computed
556      * at layout time by adding the layout_weight of each child.
557      *
558      * This can be used for instance to give a single child 50% of the total
559      * available space by giving it a layout_weight of 0.5 and setting the
560      * weightSum to 1.0.
561      *
562      * @param weightSum a number greater than 0.0f, or a number lower than or equals
563      *        to 0.0f if the weight sum should be computed from the children's
564      *        layout_weight
565      */
566     @android.view.RemotableViewMethod
setWeightSum(float weightSum)567     public void setWeightSum(float weightSum) {
568         mWeightSum = Math.max(0.0f, weightSum);
569     }
570 
571     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)572     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
573         if (mOrientation == VERTICAL) {
574             measureVertical(widthMeasureSpec, heightMeasureSpec);
575         } else {
576             measureHorizontal(widthMeasureSpec, heightMeasureSpec);
577         }
578     }
579 
580     /**
581      * Determines where to position dividers between children.
582      *
583      * @param childIndex Index of child to check for preceding divider
584      * @return true if there should be a divider before the child at childIndex
585      * @hide Pending API consideration. Currently only used internally by the system.
586      */
hasDividerBeforeChildAt(int childIndex)587     protected boolean hasDividerBeforeChildAt(int childIndex) {
588         if (childIndex == 0) {
589             return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0;
590         } else if (childIndex == getChildCount()) {
591             return (mShowDividers & SHOW_DIVIDER_END) != 0;
592         } else if ((mShowDividers & SHOW_DIVIDER_MIDDLE) != 0) {
593             boolean hasVisibleViewBefore = false;
594             for (int i = childIndex - 1; i >= 0; i--) {
595                 if (getChildAt(i).getVisibility() != GONE) {
596                     hasVisibleViewBefore = true;
597                     break;
598                 }
599             }
600             return hasVisibleViewBefore;
601         }
602         return false;
603     }
604 
605     /**
606      * Measures the children when the orientation of this LinearLayout is set
607      * to {@link #VERTICAL}.
608      *
609      * @param widthMeasureSpec Horizontal space requirements as imposed by the parent.
610      * @param heightMeasureSpec Vertical space requirements as imposed by the parent.
611      *
612      * @see #getOrientation()
613      * @see #setOrientation(int)
614      * @see #onMeasure(int, int)
615      */
measureVertical(int widthMeasureSpec, int heightMeasureSpec)616     void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
617         mTotalLength = 0;
618         int maxWidth = 0;
619         int childState = 0;
620         int alternativeMaxWidth = 0;
621         int weightedMaxWidth = 0;
622         boolean allFillParent = true;
623         float totalWeight = 0;
624 
625         final int count = getVirtualChildCount();
626 
627         final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
628         final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
629 
630         boolean matchWidth = false;
631 
632         final int baselineChildIndex = mBaselineAlignedChildIndex;
633         final boolean useLargestChild = mUseLargestChild;
634 
635         int largestChildHeight = Integer.MIN_VALUE;
636 
637         // See how tall everyone is. Also remember max width.
638         for (int i = 0; i < count; ++i) {
639             final View child = getVirtualChildAt(i);
640 
641             if (child == null) {
642                 mTotalLength += measureNullChild(i);
643                 continue;
644             }
645 
646             if (child.getVisibility() == View.GONE) {
647                i += getChildrenSkipCount(child, i);
648                continue;
649             }
650 
651             if (hasDividerBeforeChildAt(i)) {
652                 mTotalLength += mDividerHeight;
653             }
654 
655             LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
656 
657             totalWeight += lp.weight;
658 
659             if (heightMode == MeasureSpec.EXACTLY && lp.height == 0 && lp.weight > 0) {
660                 // Optimization: don't bother measuring children who are going to use
661                 // leftover space. These views will get measured again down below if
662                 // there is any leftover space.
663                 final int totalLength = mTotalLength;
664                 mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);
665             } else {
666                 int oldHeight = Integer.MIN_VALUE;
667 
668                 if (lp.height == 0 && lp.weight > 0) {
669                     // heightMode is either UNSPECIFIED or AT_MOST, and this
670                     // child wanted to stretch to fill available space.
671                     // Translate that to WRAP_CONTENT so that it does not end up
672                     // with a height of 0
673                     oldHeight = 0;
674                     lp.height = LayoutParams.WRAP_CONTENT;
675                 }
676 
677                 // Determine how big this child would like to be. If this or
678                 // previous children have given a weight, then we allow it to
679                 // use all available space (and we will shrink things later
680                 // if needed).
681                 measureChildBeforeLayout(
682                        child, i, widthMeasureSpec, 0, heightMeasureSpec,
683                        totalWeight == 0 ? mTotalLength : 0);
684 
685                 if (oldHeight != Integer.MIN_VALUE) {
686                    lp.height = oldHeight;
687                 }
688 
689                 final int childHeight = child.getMeasuredHeight();
690                 final int totalLength = mTotalLength;
691                 mTotalLength = Math.max(totalLength, totalLength + childHeight + lp.topMargin +
692                        lp.bottomMargin + getNextLocationOffset(child));
693 
694                 if (useLargestChild) {
695                     largestChildHeight = Math.max(childHeight, largestChildHeight);
696                 }
697             }
698 
699             /**
700              * If applicable, compute the additional offset to the child's baseline
701              * we'll need later when asked {@link #getBaseline}.
702              */
703             if ((baselineChildIndex >= 0) && (baselineChildIndex == i + 1)) {
704                mBaselineChildTop = mTotalLength;
705             }
706 
707             // if we are trying to use a child index for our baseline, the above
708             // book keeping only works if there are no children above it with
709             // weight.  fail fast to aid the developer.
710             if (i < baselineChildIndex && lp.weight > 0) {
711                 throw new RuntimeException("A child of LinearLayout with index "
712                         + "less than mBaselineAlignedChildIndex has weight > 0, which "
713                         + "won't work.  Either remove the weight, or don't set "
714                         + "mBaselineAlignedChildIndex.");
715             }
716 
717             boolean matchWidthLocally = false;
718             if (widthMode != MeasureSpec.EXACTLY && lp.width == LayoutParams.MATCH_PARENT) {
719                 // The width of the linear layout will scale, and at least one
720                 // child said it wanted to match our width. Set a flag
721                 // indicating that we need to remeasure at least that view when
722                 // we know our width.
723                 matchWidth = true;
724                 matchWidthLocally = true;
725             }
726 
727             final int margin = lp.leftMargin + lp.rightMargin;
728             final int measuredWidth = child.getMeasuredWidth() + margin;
729             maxWidth = Math.max(maxWidth, measuredWidth);
730             childState = combineMeasuredStates(childState, child.getMeasuredState());
731 
732             allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;
733             if (lp.weight > 0) {
734                 /*
735                  * Widths of weighted Views are bogus if we end up
736                  * remeasuring, so keep them separate.
737                  */
738                 weightedMaxWidth = Math.max(weightedMaxWidth,
739                         matchWidthLocally ? margin : measuredWidth);
740             } else {
741                 alternativeMaxWidth = Math.max(alternativeMaxWidth,
742                         matchWidthLocally ? margin : measuredWidth);
743             }
744 
745             i += getChildrenSkipCount(child, i);
746         }
747 
748         if (mTotalLength > 0 && hasDividerBeforeChildAt(count)) {
749             mTotalLength += mDividerHeight;
750         }
751 
752         if (useLargestChild &&
753                 (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED)) {
754             mTotalLength = 0;
755 
756             for (int i = 0; i < count; ++i) {
757                 final View child = getVirtualChildAt(i);
758 
759                 if (child == null) {
760                     mTotalLength += measureNullChild(i);
761                     continue;
762                 }
763 
764                 if (child.getVisibility() == GONE) {
765                     i += getChildrenSkipCount(child, i);
766                     continue;
767                 }
768 
769                 final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
770                         child.getLayoutParams();
771                 // Account for negative margins
772                 final int totalLength = mTotalLength;
773                 mTotalLength = Math.max(totalLength, totalLength + largestChildHeight +
774                         lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));
775             }
776         }
777 
778         // Add in our padding
779         mTotalLength += mPaddingTop + mPaddingBottom;
780 
781         int heightSize = mTotalLength;
782 
783         // Check against our minimum height
784         heightSize = Math.max(heightSize, getSuggestedMinimumHeight());
785 
786         // Reconcile our calculated size with the heightMeasureSpec
787         int heightSizeAndState = resolveSizeAndState(heightSize, heightMeasureSpec, 0);
788         heightSize = heightSizeAndState & MEASURED_SIZE_MASK;
789 
790         // Either expand children with weight to take up available space or
791         // shrink them if they extend beyond our current bounds
792         int delta = heightSize - mTotalLength;
793         if (delta != 0 && totalWeight > 0.0f) {
794             float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
795 
796             mTotalLength = 0;
797 
798             for (int i = 0; i < count; ++i) {
799                 final View child = getVirtualChildAt(i);
800 
801                 if (child.getVisibility() == View.GONE) {
802                     continue;
803                 }
804 
805                 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
806 
807                 float childExtra = lp.weight;
808                 if (childExtra > 0) {
809                     // Child said it could absorb extra space -- give him his share
810                     int share = (int) (childExtra * delta / weightSum);
811                     weightSum -= childExtra;
812                     delta -= share;
813 
814                     final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
815                             mPaddingLeft + mPaddingRight +
816                                     lp.leftMargin + lp.rightMargin, lp.width);
817 
818                     // TODO: Use a field like lp.isMeasured to figure out if this
819                     // child has been previously measured
820                     if ((lp.height != 0) || (heightMode != MeasureSpec.EXACTLY)) {
821                         // child was measured once already above...
822                         // base new measurement on stored values
823                         int childHeight = child.getMeasuredHeight() + share;
824                         if (childHeight < 0) {
825                             childHeight = 0;
826                         }
827 
828                         child.measure(childWidthMeasureSpec,
829                                 MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY));
830                     } else {
831                         // child was skipped in the loop above.
832                         // Measure for this first time here
833                         child.measure(childWidthMeasureSpec,
834                                 MeasureSpec.makeMeasureSpec(share > 0 ? share : 0,
835                                         MeasureSpec.EXACTLY));
836                     }
837 
838                     // Child may now not fit in vertical dimension.
839                     childState = combineMeasuredStates(childState, child.getMeasuredState()
840                             & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT));
841                 }
842 
843                 final int margin =  lp.leftMargin + lp.rightMargin;
844                 final int measuredWidth = child.getMeasuredWidth() + margin;
845                 maxWidth = Math.max(maxWidth, measuredWidth);
846 
847                 boolean matchWidthLocally = widthMode != MeasureSpec.EXACTLY &&
848                         lp.width == LayoutParams.MATCH_PARENT;
849 
850                 alternativeMaxWidth = Math.max(alternativeMaxWidth,
851                         matchWidthLocally ? margin : measuredWidth);
852 
853                 allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;
854 
855                 final int totalLength = mTotalLength;
856                 mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredHeight() +
857                         lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));
858             }
859 
860             // Add in our padding
861             mTotalLength += mPaddingTop + mPaddingBottom;
862             // TODO: Should we recompute the heightSpec based on the new total length?
863         } else {
864             alternativeMaxWidth = Math.max(alternativeMaxWidth,
865                                            weightedMaxWidth);
866 
867 
868             // We have no limit, so make all weighted views as tall as the largest child.
869             // Children will have already been measured once.
870             if (useLargestChild && heightMode != MeasureSpec.EXACTLY) {
871                 for (int i = 0; i < count; i++) {
872                     final View child = getVirtualChildAt(i);
873 
874                     if (child == null || child.getVisibility() == View.GONE) {
875                         continue;
876                     }
877 
878                     final LinearLayout.LayoutParams lp =
879                             (LinearLayout.LayoutParams) child.getLayoutParams();
880 
881                     float childExtra = lp.weight;
882                     if (childExtra > 0) {
883                         child.measure(
884                                 MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(),
885                                         MeasureSpec.EXACTLY),
886                                 MeasureSpec.makeMeasureSpec(largestChildHeight,
887                                         MeasureSpec.EXACTLY));
888                     }
889                 }
890             }
891         }
892 
893         if (!allFillParent && widthMode != MeasureSpec.EXACTLY) {
894             maxWidth = alternativeMaxWidth;
895         }
896 
897         maxWidth += mPaddingLeft + mPaddingRight;
898 
899         // Check against our minimum width
900         maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
901 
902         setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
903                 heightSizeAndState);
904 
905         if (matchWidth) {
906             forceUniformWidth(count, heightMeasureSpec);
907         }
908     }
909 
forceUniformWidth(int count, int heightMeasureSpec)910     private void forceUniformWidth(int count, int heightMeasureSpec) {
911         // Pretend that the linear layout has an exact size.
912         int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(),
913                 MeasureSpec.EXACTLY);
914         for (int i = 0; i< count; ++i) {
915            final View child = getVirtualChildAt(i);
916            if (child.getVisibility() != GONE) {
917                LinearLayout.LayoutParams lp = ((LinearLayout.LayoutParams)child.getLayoutParams());
918 
919                if (lp.width == LayoutParams.MATCH_PARENT) {
920                    // Temporarily force children to reuse their old measured height
921                    // FIXME: this may not be right for something like wrapping text?
922                    int oldHeight = lp.height;
923                    lp.height = child.getMeasuredHeight();
924 
925                    // Remeasue with new dimensions
926                    measureChildWithMargins(child, uniformMeasureSpec, 0, heightMeasureSpec, 0);
927                    lp.height = oldHeight;
928                }
929            }
930         }
931     }
932 
933     /**
934      * Measures the children when the orientation of this LinearLayout is set
935      * to {@link #HORIZONTAL}.
936      *
937      * @param widthMeasureSpec Horizontal space requirements as imposed by the parent.
938      * @param heightMeasureSpec Vertical space requirements as imposed by the parent.
939      *
940      * @see #getOrientation()
941      * @see #setOrientation(int)
942      * @see #onMeasure(int, int)
943      */
measureHorizontal(int widthMeasureSpec, int heightMeasureSpec)944     void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec) {
945         mTotalLength = 0;
946         int maxHeight = 0;
947         int childState = 0;
948         int alternativeMaxHeight = 0;
949         int weightedMaxHeight = 0;
950         boolean allFillParent = true;
951         float totalWeight = 0;
952 
953         final int count = getVirtualChildCount();
954 
955         final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
956         final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
957 
958         boolean matchHeight = false;
959 
960         if (mMaxAscent == null || mMaxDescent == null) {
961             mMaxAscent = new int[VERTICAL_GRAVITY_COUNT];
962             mMaxDescent = new int[VERTICAL_GRAVITY_COUNT];
963         }
964 
965         final int[] maxAscent = mMaxAscent;
966         final int[] maxDescent = mMaxDescent;
967 
968         maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
969         maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;
970 
971         final boolean baselineAligned = mBaselineAligned;
972         final boolean useLargestChild = mUseLargestChild;
973 
974         final boolean isExactly = widthMode == MeasureSpec.EXACTLY;
975 
976         int largestChildWidth = Integer.MIN_VALUE;
977 
978         // See how wide everyone is. Also remember max height.
979         for (int i = 0; i < count; ++i) {
980             final View child = getVirtualChildAt(i);
981 
982             if (child == null) {
983                 mTotalLength += measureNullChild(i);
984                 continue;
985             }
986 
987             if (child.getVisibility() == GONE) {
988                 i += getChildrenSkipCount(child, i);
989                 continue;
990             }
991 
992             if (hasDividerBeforeChildAt(i)) {
993                 mTotalLength += mDividerWidth;
994             }
995 
996             final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
997                     child.getLayoutParams();
998 
999             totalWeight += lp.weight;
1000 
1001             if (widthMode == MeasureSpec.EXACTLY && lp.width == 0 && lp.weight > 0) {
1002                 // Optimization: don't bother measuring children who are going to use
1003                 // leftover space. These views will get measured again down below if
1004                 // there is any leftover space.
1005                 if (isExactly) {
1006                     mTotalLength += lp.leftMargin + lp.rightMargin;
1007                 } else {
1008                     final int totalLength = mTotalLength;
1009                     mTotalLength = Math.max(totalLength, totalLength +
1010                             lp.leftMargin + lp.rightMargin);
1011                 }
1012 
1013                 // Baseline alignment requires to measure widgets to obtain the
1014                 // baseline offset (in particular for TextViews). The following
1015                 // defeats the optimization mentioned above. Allow the child to
1016                 // use as much space as it wants because we can shrink things
1017                 // later (and re-measure).
1018                 if (baselineAligned) {
1019                     final int freeSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
1020                     child.measure(freeSpec, freeSpec);
1021                 }
1022             } else {
1023                 int oldWidth = Integer.MIN_VALUE;
1024 
1025                 if (lp.width == 0 && lp.weight > 0) {
1026                     // widthMode is either UNSPECIFIED or AT_MOST, and this
1027                     // child
1028                     // wanted to stretch to fill available space. Translate that to
1029                     // WRAP_CONTENT so that it does not end up with a width of 0
1030                     oldWidth = 0;
1031                     lp.width = LayoutParams.WRAP_CONTENT;
1032                 }
1033 
1034                 // Determine how big this child would like to be. If this or
1035                 // previous children have given a weight, then we allow it to
1036                 // use all available space (and we will shrink things later
1037                 // if needed).
1038                 measureChildBeforeLayout(child, i, widthMeasureSpec,
1039                         totalWeight == 0 ? mTotalLength : 0,
1040                         heightMeasureSpec, 0);
1041 
1042                 if (oldWidth != Integer.MIN_VALUE) {
1043                     lp.width = oldWidth;
1044                 }
1045 
1046                 final int childWidth = child.getMeasuredWidth();
1047                 if (isExactly) {
1048                     mTotalLength += childWidth + lp.leftMargin + lp.rightMargin +
1049                             getNextLocationOffset(child);
1050                 } else {
1051                     final int totalLength = mTotalLength;
1052                     mTotalLength = Math.max(totalLength, totalLength + childWidth + lp.leftMargin +
1053                            lp.rightMargin + getNextLocationOffset(child));
1054                 }
1055 
1056                 if (useLargestChild) {
1057                     largestChildWidth = Math.max(childWidth, largestChildWidth);
1058                 }
1059             }
1060 
1061             boolean matchHeightLocally = false;
1062             if (heightMode != MeasureSpec.EXACTLY && lp.height == LayoutParams.MATCH_PARENT) {
1063                 // The height of the linear layout will scale, and at least one
1064                 // child said it wanted to match our height. Set a flag indicating that
1065                 // we need to remeasure at least that view when we know our height.
1066                 matchHeight = true;
1067                 matchHeightLocally = true;
1068             }
1069 
1070             final int margin = lp.topMargin + lp.bottomMargin;
1071             final int childHeight = child.getMeasuredHeight() + margin;
1072             childState = combineMeasuredStates(childState, child.getMeasuredState());
1073 
1074             if (baselineAligned) {
1075                 final int childBaseline = child.getBaseline();
1076                 if (childBaseline != -1) {
1077                     // Translates the child's vertical gravity into an index
1078                     // in the range 0..VERTICAL_GRAVITY_COUNT
1079                     final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity)
1080                             & Gravity.VERTICAL_GRAVITY_MASK;
1081                     final int index = ((gravity >> Gravity.AXIS_Y_SHIFT)
1082                             & ~Gravity.AXIS_SPECIFIED) >> 1;
1083 
1084                     maxAscent[index] = Math.max(maxAscent[index], childBaseline);
1085                     maxDescent[index] = Math.max(maxDescent[index], childHeight - childBaseline);
1086                 }
1087             }
1088 
1089             maxHeight = Math.max(maxHeight, childHeight);
1090 
1091             allFillParent = allFillParent && lp.height == LayoutParams.MATCH_PARENT;
1092             if (lp.weight > 0) {
1093                 /*
1094                  * Heights of weighted Views are bogus if we end up
1095                  * remeasuring, so keep them separate.
1096                  */
1097                 weightedMaxHeight = Math.max(weightedMaxHeight,
1098                         matchHeightLocally ? margin : childHeight);
1099             } else {
1100                 alternativeMaxHeight = Math.max(alternativeMaxHeight,
1101                         matchHeightLocally ? margin : childHeight);
1102             }
1103 
1104             i += getChildrenSkipCount(child, i);
1105         }
1106 
1107         if (mTotalLength > 0 && hasDividerBeforeChildAt(count)) {
1108             mTotalLength += mDividerWidth;
1109         }
1110 
1111         // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP,
1112         // the most common case
1113         if (maxAscent[INDEX_TOP] != -1 ||
1114                 maxAscent[INDEX_CENTER_VERTICAL] != -1 ||
1115                 maxAscent[INDEX_BOTTOM] != -1 ||
1116                 maxAscent[INDEX_FILL] != -1) {
1117             final int ascent = Math.max(maxAscent[INDEX_FILL],
1118                     Math.max(maxAscent[INDEX_CENTER_VERTICAL],
1119                     Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM])));
1120             final int descent = Math.max(maxDescent[INDEX_FILL],
1121                     Math.max(maxDescent[INDEX_CENTER_VERTICAL],
1122                     Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM])));
1123             maxHeight = Math.max(maxHeight, ascent + descent);
1124         }
1125 
1126         if (useLargestChild &&
1127                 (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.UNSPECIFIED)) {
1128             mTotalLength = 0;
1129 
1130             for (int i = 0; i < count; ++i) {
1131                 final View child = getVirtualChildAt(i);
1132 
1133                 if (child == null) {
1134                     mTotalLength += measureNullChild(i);
1135                     continue;
1136                 }
1137 
1138                 if (child.getVisibility() == GONE) {
1139                     i += getChildrenSkipCount(child, i);
1140                     continue;
1141                 }
1142 
1143                 final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
1144                         child.getLayoutParams();
1145                 if (isExactly) {
1146                     mTotalLength += largestChildWidth + lp.leftMargin + lp.rightMargin +
1147                             getNextLocationOffset(child);
1148                 } else {
1149                     final int totalLength = mTotalLength;
1150                     mTotalLength = Math.max(totalLength, totalLength + largestChildWidth +
1151                             lp.leftMargin + lp.rightMargin + getNextLocationOffset(child));
1152                 }
1153             }
1154         }
1155 
1156         // Add in our padding
1157         mTotalLength += mPaddingLeft + mPaddingRight;
1158 
1159         int widthSize = mTotalLength;
1160 
1161         // Check against our minimum width
1162         widthSize = Math.max(widthSize, getSuggestedMinimumWidth());
1163 
1164         // Reconcile our calculated size with the widthMeasureSpec
1165         int widthSizeAndState = resolveSizeAndState(widthSize, widthMeasureSpec, 0);
1166         widthSize = widthSizeAndState & MEASURED_SIZE_MASK;
1167 
1168         // Either expand children with weight to take up available space or
1169         // shrink them if they extend beyond our current bounds
1170         int delta = widthSize - mTotalLength;
1171         if (delta != 0 && totalWeight > 0.0f) {
1172             float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
1173 
1174             maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
1175             maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;
1176             maxHeight = -1;
1177 
1178             mTotalLength = 0;
1179 
1180             for (int i = 0; i < count; ++i) {
1181                 final View child = getVirtualChildAt(i);
1182 
1183                 if (child == null || child.getVisibility() == View.GONE) {
1184                     continue;
1185                 }
1186 
1187                 final LinearLayout.LayoutParams lp =
1188                         (LinearLayout.LayoutParams) child.getLayoutParams();
1189 
1190                 float childExtra = lp.weight;
1191                 if (childExtra > 0) {
1192                     // Child said it could absorb extra space -- give him his share
1193                     int share = (int) (childExtra * delta / weightSum);
1194                     weightSum -= childExtra;
1195                     delta -= share;
1196 
1197                     final int childHeightMeasureSpec = getChildMeasureSpec(
1198                             heightMeasureSpec,
1199                             mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin,
1200                             lp.height);
1201 
1202                     // TODO: Use a field like lp.isMeasured to figure out if this
1203                     // child has been previously measured
1204                     if ((lp.width != 0) || (widthMode != MeasureSpec.EXACTLY)) {
1205                         // child was measured once already above ... base new measurement
1206                         // on stored values
1207                         int childWidth = child.getMeasuredWidth() + share;
1208                         if (childWidth < 0) {
1209                             childWidth = 0;
1210                         }
1211 
1212                         child.measure(
1213                             MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
1214                             childHeightMeasureSpec);
1215                     } else {
1216                         // child was skipped in the loop above. Measure for this first time here
1217                         child.measure(MeasureSpec.makeMeasureSpec(
1218                                 share > 0 ? share : 0, MeasureSpec.EXACTLY),
1219                                 childHeightMeasureSpec);
1220                     }
1221 
1222                     // Child may now not fit in horizontal dimension.
1223                     childState = combineMeasuredStates(childState,
1224                             child.getMeasuredState() & MEASURED_STATE_MASK);
1225                 }
1226 
1227                 if (isExactly) {
1228                     mTotalLength += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin +
1229                             getNextLocationOffset(child);
1230                 } else {
1231                     final int totalLength = mTotalLength;
1232                     mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredWidth() +
1233                             lp.leftMargin + lp.rightMargin + getNextLocationOffset(child));
1234                 }
1235 
1236                 boolean matchHeightLocally = heightMode != MeasureSpec.EXACTLY &&
1237                         lp.height == LayoutParams.MATCH_PARENT;
1238 
1239                 final int margin = lp.topMargin + lp .bottomMargin;
1240                 int childHeight = child.getMeasuredHeight() + margin;
1241                 maxHeight = Math.max(maxHeight, childHeight);
1242                 alternativeMaxHeight = Math.max(alternativeMaxHeight,
1243                         matchHeightLocally ? margin : childHeight);
1244 
1245                 allFillParent = allFillParent && lp.height == LayoutParams.MATCH_PARENT;
1246 
1247                 if (baselineAligned) {
1248                     final int childBaseline = child.getBaseline();
1249                     if (childBaseline != -1) {
1250                         // Translates the child's vertical gravity into an index in the range 0..2
1251                         final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity)
1252                                 & Gravity.VERTICAL_GRAVITY_MASK;
1253                         final int index = ((gravity >> Gravity.AXIS_Y_SHIFT)
1254                                 & ~Gravity.AXIS_SPECIFIED) >> 1;
1255 
1256                         maxAscent[index] = Math.max(maxAscent[index], childBaseline);
1257                         maxDescent[index] = Math.max(maxDescent[index],
1258                                 childHeight - childBaseline);
1259                     }
1260                 }
1261             }
1262 
1263             // Add in our padding
1264             mTotalLength += mPaddingLeft + mPaddingRight;
1265             // TODO: Should we update widthSize with the new total length?
1266 
1267             // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP,
1268             // the most common case
1269             if (maxAscent[INDEX_TOP] != -1 ||
1270                     maxAscent[INDEX_CENTER_VERTICAL] != -1 ||
1271                     maxAscent[INDEX_BOTTOM] != -1 ||
1272                     maxAscent[INDEX_FILL] != -1) {
1273                 final int ascent = Math.max(maxAscent[INDEX_FILL],
1274                         Math.max(maxAscent[INDEX_CENTER_VERTICAL],
1275                         Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM])));
1276                 final int descent = Math.max(maxDescent[INDEX_FILL],
1277                         Math.max(maxDescent[INDEX_CENTER_VERTICAL],
1278                         Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM])));
1279                 maxHeight = Math.max(maxHeight, ascent + descent);
1280             }
1281         } else {
1282             alternativeMaxHeight = Math.max(alternativeMaxHeight, weightedMaxHeight);
1283 
1284             // We have no limit, so make all weighted views as wide as the largest child.
1285             // Children will have already been measured once.
1286             if (useLargestChild && widthMode != MeasureSpec.EXACTLY) {
1287                 for (int i = 0; i < count; i++) {
1288                     final View child = getVirtualChildAt(i);
1289 
1290                     if (child == null || child.getVisibility() == View.GONE) {
1291                         continue;
1292                     }
1293 
1294                     final LinearLayout.LayoutParams lp =
1295                             (LinearLayout.LayoutParams) child.getLayoutParams();
1296 
1297                     float childExtra = lp.weight;
1298                     if (childExtra > 0) {
1299                         child.measure(
1300                                 MeasureSpec.makeMeasureSpec(largestChildWidth, MeasureSpec.EXACTLY),
1301                                 MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(),
1302                                         MeasureSpec.EXACTLY));
1303                     }
1304                 }
1305             }
1306         }
1307 
1308         if (!allFillParent && heightMode != MeasureSpec.EXACTLY) {
1309             maxHeight = alternativeMaxHeight;
1310         }
1311 
1312         maxHeight += mPaddingTop + mPaddingBottom;
1313 
1314         // Check against our minimum height
1315         maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
1316 
1317         setMeasuredDimension(widthSizeAndState | (childState&MEASURED_STATE_MASK),
1318                 resolveSizeAndState(maxHeight, heightMeasureSpec,
1319                         (childState<<MEASURED_HEIGHT_STATE_SHIFT)));
1320 
1321         if (matchHeight) {
1322             forceUniformHeight(count, widthMeasureSpec);
1323         }
1324     }
1325 
forceUniformHeight(int count, int widthMeasureSpec)1326     private void forceUniformHeight(int count, int widthMeasureSpec) {
1327         // Pretend that the linear layout has an exact size. This is the measured height of
1328         // ourselves. The measured height should be the max height of the children, changed
1329         // to accomodate the heightMesureSpec from the parent
1330         int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(),
1331                 MeasureSpec.EXACTLY);
1332         for (int i = 0; i < count; ++i) {
1333            final View child = getVirtualChildAt(i);
1334            if (child.getVisibility() != GONE) {
1335                LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
1336 
1337                if (lp.height == LayoutParams.MATCH_PARENT) {
1338                    // Temporarily force children to reuse their old measured width
1339                    // FIXME: this may not be right for something like wrapping text?
1340                    int oldWidth = lp.width;
1341                    lp.width = child.getMeasuredWidth();
1342 
1343                    // Remeasure with new dimensions
1344                    measureChildWithMargins(child, widthMeasureSpec, 0, uniformMeasureSpec, 0);
1345                    lp.width = oldWidth;
1346                }
1347            }
1348         }
1349     }
1350 
1351     /**
1352      * <p>Returns the number of children to skip after measuring/laying out
1353      * the specified child.</p>
1354      *
1355      * @param child the child after which we want to skip children
1356      * @param index the index of the child after which we want to skip children
1357      * @return the number of children to skip, 0 by default
1358      */
getChildrenSkipCount(View child, int index)1359     int getChildrenSkipCount(View child, int index) {
1360         return 0;
1361     }
1362 
1363     /**
1364      * <p>Returns the size (width or height) that should be occupied by a null
1365      * child.</p>
1366      *
1367      * @param childIndex the index of the null child
1368      * @return the width or height of the child depending on the orientation
1369      */
measureNullChild(int childIndex)1370     int measureNullChild(int childIndex) {
1371         return 0;
1372     }
1373 
1374     /**
1375      * <p>Measure the child according to the parent's measure specs. This
1376      * method should be overriden by subclasses to force the sizing of
1377      * children. This method is called by {@link #measureVertical(int, int)} and
1378      * {@link #measureHorizontal(int, int)}.</p>
1379      *
1380      * @param child the child to measure
1381      * @param childIndex the index of the child in this view
1382      * @param widthMeasureSpec horizontal space requirements as imposed by the parent
1383      * @param totalWidth extra space that has been used up by the parent horizontally
1384      * @param heightMeasureSpec vertical space requirements as imposed by the parent
1385      * @param totalHeight extra space that has been used up by the parent vertically
1386      */
measureChildBeforeLayout(View child, int childIndex, int widthMeasureSpec, int totalWidth, int heightMeasureSpec, int totalHeight)1387     void measureChildBeforeLayout(View child, int childIndex,
1388             int widthMeasureSpec, int totalWidth, int heightMeasureSpec,
1389             int totalHeight) {
1390         measureChildWithMargins(child, widthMeasureSpec, totalWidth,
1391                 heightMeasureSpec, totalHeight);
1392     }
1393 
1394     /**
1395      * <p>Return the location offset of the specified child. This can be used
1396      * by subclasses to change the location of a given widget.</p>
1397      *
1398      * @param child the child for which to obtain the location offset
1399      * @return the location offset in pixels
1400      */
getLocationOffset(View child)1401     int getLocationOffset(View child) {
1402         return 0;
1403     }
1404 
1405     /**
1406      * <p>Return the size offset of the next sibling of the specified child.
1407      * This can be used by subclasses to change the location of the widget
1408      * following <code>child</code>.</p>
1409      *
1410      * @param child the child whose next sibling will be moved
1411      * @return the location offset of the next child in pixels
1412      */
getNextLocationOffset(View child)1413     int getNextLocationOffset(View child) {
1414         return 0;
1415     }
1416 
1417     @Override
onLayout(boolean changed, int l, int t, int r, int b)1418     protected void onLayout(boolean changed, int l, int t, int r, int b) {
1419         if (mOrientation == VERTICAL) {
1420             layoutVertical();
1421         } else {
1422             layoutHorizontal();
1423         }
1424     }
1425 
1426     /**
1427      * Position the children during a layout pass if the orientation of this
1428      * LinearLayout is set to {@link #VERTICAL}.
1429      *
1430      * @see #getOrientation()
1431      * @see #setOrientation(int)
1432      * @see #onLayout(boolean, int, int, int, int)
1433      */
layoutVertical()1434     void layoutVertical() {
1435         final int paddingLeft = mPaddingLeft;
1436 
1437         int childTop;
1438         int childLeft;
1439 
1440         // Where right end of child should go
1441         final int width = mRight - mLeft;
1442         int childRight = width - mPaddingRight;
1443 
1444         // Space available for child
1445         int childSpace = width - paddingLeft - mPaddingRight;
1446 
1447         final int count = getVirtualChildCount();
1448 
1449         final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
1450         final int minorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
1451 
1452         switch (majorGravity) {
1453            case Gravity.BOTTOM:
1454                // mTotalLength contains the padding already
1455                childTop = mPaddingTop + mBottom - mTop - mTotalLength;
1456                break;
1457 
1458                // mTotalLength contains the padding already
1459            case Gravity.CENTER_VERTICAL:
1460                childTop = mPaddingTop + (mBottom - mTop - mTotalLength) / 2;
1461                break;
1462 
1463            case Gravity.TOP:
1464            default:
1465                childTop = mPaddingTop;
1466                break;
1467         }
1468 
1469         for (int i = 0; i < count; i++) {
1470             final View child = getVirtualChildAt(i);
1471             if (child == null) {
1472                 childTop += measureNullChild(i);
1473             } else if (child.getVisibility() != GONE) {
1474                 final int childWidth = child.getMeasuredWidth();
1475                 final int childHeight = child.getMeasuredHeight();
1476 
1477                 final LinearLayout.LayoutParams lp =
1478                         (LinearLayout.LayoutParams) child.getLayoutParams();
1479 
1480                 int gravity = lp.gravity;
1481                 if (gravity < 0) {
1482                     gravity = minorGravity;
1483                 }
1484                 final int layoutDirection = getResolvedLayoutDirection();
1485                 final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
1486                 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
1487                     case Gravity.CENTER_HORIZONTAL:
1488                         childLeft = paddingLeft + ((childSpace - childWidth) / 2)
1489                                 + lp.leftMargin - lp.rightMargin;
1490                         break;
1491 
1492                     case Gravity.RIGHT:
1493                         childLeft = childRight - childWidth - lp.rightMargin;
1494                         break;
1495 
1496                     case Gravity.LEFT:
1497                     default:
1498                         childLeft = paddingLeft + lp.leftMargin;
1499                         break;
1500                 }
1501 
1502                 if (hasDividerBeforeChildAt(i)) {
1503                     childTop += mDividerHeight;
1504                 }
1505 
1506                 childTop += lp.topMargin;
1507                 setChildFrame(child, childLeft, childTop + getLocationOffset(child),
1508                         childWidth, childHeight);
1509                 childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);
1510 
1511                 i += getChildrenSkipCount(child, i);
1512             }
1513         }
1514     }
1515 
1516     /**
1517      * Position the children during a layout pass if the orientation of this
1518      * LinearLayout is set to {@link #HORIZONTAL}.
1519      *
1520      * @see #getOrientation()
1521      * @see #setOrientation(int)
1522      * @see #onLayout(boolean, int, int, int, int)
1523      */
layoutHorizontal()1524     void layoutHorizontal() {
1525         final boolean isLayoutRtl = isLayoutRtl();
1526         final int paddingTop = mPaddingTop;
1527 
1528         int childTop;
1529         int childLeft;
1530 
1531         // Where bottom of child should go
1532         final int height = mBottom - mTop;
1533         int childBottom = height - mPaddingBottom;
1534 
1535         // Space available for child
1536         int childSpace = height - paddingTop - mPaddingBottom;
1537 
1538         final int count = getVirtualChildCount();
1539 
1540         final int majorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
1541         final int minorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
1542 
1543         final boolean baselineAligned = mBaselineAligned;
1544 
1545         final int[] maxAscent = mMaxAscent;
1546         final int[] maxDescent = mMaxDescent;
1547 
1548         final int layoutDirection = getResolvedLayoutDirection();
1549         switch (Gravity.getAbsoluteGravity(majorGravity, layoutDirection)) {
1550             case Gravity.RIGHT:
1551                 // mTotalLength contains the padding already
1552                 childLeft = mPaddingLeft + mRight - mLeft - mTotalLength;
1553                 break;
1554 
1555             case Gravity.CENTER_HORIZONTAL:
1556                 // mTotalLength contains the padding already
1557                 childLeft = mPaddingLeft + (mRight - mLeft - mTotalLength) / 2;
1558                 break;
1559 
1560             case Gravity.LEFT:
1561             default:
1562                 childLeft = mPaddingLeft;
1563                 break;
1564         }
1565 
1566         int start = 0;
1567         int dir = 1;
1568         //In case of RTL, start drawing from the last child.
1569         if (isLayoutRtl) {
1570             start = count - 1;
1571             dir = -1;
1572         }
1573 
1574         for (int i = 0; i < count; i++) {
1575             int childIndex = start + dir * i;
1576             final View child = getVirtualChildAt(childIndex);
1577 
1578             if (child == null) {
1579                 childLeft += measureNullChild(childIndex);
1580             } else if (child.getVisibility() != GONE) {
1581                 final int childWidth = child.getMeasuredWidth();
1582                 final int childHeight = child.getMeasuredHeight();
1583                 int childBaseline = -1;
1584 
1585                 final LinearLayout.LayoutParams lp =
1586                         (LinearLayout.LayoutParams) child.getLayoutParams();
1587 
1588                 if (baselineAligned && lp.height != LayoutParams.MATCH_PARENT) {
1589                     childBaseline = child.getBaseline();
1590                 }
1591 
1592                 int gravity = lp.gravity;
1593                 if (gravity < 0) {
1594                     gravity = minorGravity;
1595                 }
1596 
1597                 switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
1598                     case Gravity.TOP:
1599                         childTop = paddingTop + lp.topMargin;
1600                         if (childBaseline != -1) {
1601                             childTop += maxAscent[INDEX_TOP] - childBaseline;
1602                         }
1603                         break;
1604 
1605                     case Gravity.CENTER_VERTICAL:
1606                         // Removed support for baseline alignment when layout_gravity or
1607                         // gravity == center_vertical. See bug #1038483.
1608                         // Keep the code around if we need to re-enable this feature
1609                         // if (childBaseline != -1) {
1610                         //     // Align baselines vertically only if the child is smaller than us
1611                         //     if (childSpace - childHeight > 0) {
1612                         //         childTop = paddingTop + (childSpace / 2) - childBaseline;
1613                         //     } else {
1614                         //         childTop = paddingTop + (childSpace - childHeight) / 2;
1615                         //     }
1616                         // } else {
1617                         childTop = paddingTop + ((childSpace - childHeight) / 2)
1618                                 + lp.topMargin - lp.bottomMargin;
1619                         break;
1620 
1621                     case Gravity.BOTTOM:
1622                         childTop = childBottom - childHeight - lp.bottomMargin;
1623                         if (childBaseline != -1) {
1624                             int descent = child.getMeasuredHeight() - childBaseline;
1625                             childTop -= (maxDescent[INDEX_BOTTOM] - descent);
1626                         }
1627                         break;
1628                     default:
1629                         childTop = paddingTop;
1630                         break;
1631                 }
1632 
1633                 if (hasDividerBeforeChildAt(childIndex)) {
1634                     childLeft += mDividerWidth;
1635                 }
1636 
1637                 childLeft += lp.leftMargin;
1638                 setChildFrame(child, childLeft + getLocationOffset(child), childTop,
1639                         childWidth, childHeight);
1640                 childLeft += childWidth + lp.rightMargin +
1641                         getNextLocationOffset(child);
1642 
1643                 i += getChildrenSkipCount(child, childIndex);
1644             }
1645         }
1646     }
1647 
setChildFrame(View child, int left, int top, int width, int height)1648     private void setChildFrame(View child, int left, int top, int width, int height) {
1649         child.layout(left, top, left + width, top + height);
1650     }
1651 
1652     /**
1653      * Should the layout be a column or a row.
1654      * @param orientation Pass HORIZONTAL or VERTICAL. Default
1655      * value is HORIZONTAL.
1656      *
1657      * @attr ref android.R.styleable#LinearLayout_orientation
1658      */
setOrientation(int orientation)1659     public void setOrientation(int orientation) {
1660         if (mOrientation != orientation) {
1661             mOrientation = orientation;
1662             requestLayout();
1663         }
1664     }
1665 
1666     /**
1667      * Returns the current orientation.
1668      *
1669      * @return either {@link #HORIZONTAL} or {@link #VERTICAL}
1670      */
getOrientation()1671     public int getOrientation() {
1672         return mOrientation;
1673     }
1674 
1675     /**
1676      * Describes how the child views are positioned. Defaults to GRAVITY_TOP. If
1677      * this layout has a VERTICAL orientation, this controls where all the child
1678      * views are placed if there is extra vertical space. If this layout has a
1679      * HORIZONTAL orientation, this controls the alignment of the children.
1680      *
1681      * @param gravity See {@link android.view.Gravity}
1682      *
1683      * @attr ref android.R.styleable#LinearLayout_gravity
1684      */
1685     @android.view.RemotableViewMethod
setGravity(int gravity)1686     public void setGravity(int gravity) {
1687         if (mGravity != gravity) {
1688             if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
1689                 gravity |= Gravity.START;
1690             }
1691 
1692             if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
1693                 gravity |= Gravity.TOP;
1694             }
1695 
1696             mGravity = gravity;
1697             requestLayout();
1698         }
1699     }
1700 
1701     @android.view.RemotableViewMethod
setHorizontalGravity(int horizontalGravity)1702     public void setHorizontalGravity(int horizontalGravity) {
1703         final int gravity = horizontalGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
1704         if ((mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) != gravity) {
1705             mGravity = (mGravity & ~Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) | gravity;
1706             requestLayout();
1707         }
1708     }
1709 
1710     @android.view.RemotableViewMethod
setVerticalGravity(int verticalGravity)1711     public void setVerticalGravity(int verticalGravity) {
1712         final int gravity = verticalGravity & Gravity.VERTICAL_GRAVITY_MASK;
1713         if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != gravity) {
1714             mGravity = (mGravity & ~Gravity.VERTICAL_GRAVITY_MASK) | gravity;
1715             requestLayout();
1716         }
1717     }
1718 
1719     @Override
generateLayoutParams(AttributeSet attrs)1720     public LayoutParams generateLayoutParams(AttributeSet attrs) {
1721         return new LinearLayout.LayoutParams(getContext(), attrs);
1722     }
1723 
1724     /**
1725      * Returns a set of layout parameters with a width of
1726      * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT}
1727      * and a height of {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}
1728      * when the layout's orientation is {@link #VERTICAL}. When the orientation is
1729      * {@link #HORIZONTAL}, the width is set to {@link LayoutParams#WRAP_CONTENT}
1730      * and the height to {@link LayoutParams#WRAP_CONTENT}.
1731      */
1732     @Override
generateDefaultLayoutParams()1733     protected LayoutParams generateDefaultLayoutParams() {
1734         if (mOrientation == HORIZONTAL) {
1735             return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
1736         } else if (mOrientation == VERTICAL) {
1737             return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
1738         }
1739         return null;
1740     }
1741 
1742     @Override
generateLayoutParams(ViewGroup.LayoutParams p)1743     protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
1744         return new LayoutParams(p);
1745     }
1746 
1747 
1748     // Override to allow type-checking of LayoutParams.
1749     @Override
checkLayoutParams(ViewGroup.LayoutParams p)1750     protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
1751         return p instanceof LinearLayout.LayoutParams;
1752     }
1753 
1754     @Override
onInitializeAccessibilityEvent(AccessibilityEvent event)1755     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
1756         super.onInitializeAccessibilityEvent(event);
1757         event.setClassName(LinearLayout.class.getName());
1758     }
1759 
1760     @Override
onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info)1761     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
1762         super.onInitializeAccessibilityNodeInfo(info);
1763         info.setClassName(LinearLayout.class.getName());
1764     }
1765 
1766     /**
1767      * Per-child layout information associated with ViewLinearLayout.
1768      *
1769      * @attr ref android.R.styleable#LinearLayout_Layout_layout_weight
1770      * @attr ref android.R.styleable#LinearLayout_Layout_layout_gravity
1771      */
1772     public static class LayoutParams extends ViewGroup.MarginLayoutParams {
1773         /**
1774          * Indicates how much of the extra space in the LinearLayout will be
1775          * allocated to the view associated with these LayoutParams. Specify
1776          * 0 if the view should not be stretched. Otherwise the extra pixels
1777          * will be pro-rated among all views whose weight is greater than 0.
1778          */
1779         @ViewDebug.ExportedProperty(category = "layout")
1780         public float weight;
1781 
1782         /**
1783          * Gravity for the view associated with these LayoutParams.
1784          *
1785          * @see android.view.Gravity
1786          */
1787         @ViewDebug.ExportedProperty(category = "layout", mapping = {
1788             @ViewDebug.IntToString(from =  -1,                       to = "NONE"),
1789             @ViewDebug.IntToString(from = Gravity.NO_GRAVITY,        to = "NONE"),
1790             @ViewDebug.IntToString(from = Gravity.TOP,               to = "TOP"),
1791             @ViewDebug.IntToString(from = Gravity.BOTTOM,            to = "BOTTOM"),
1792             @ViewDebug.IntToString(from = Gravity.LEFT,              to = "LEFT"),
1793             @ViewDebug.IntToString(from = Gravity.RIGHT,             to = "RIGHT"),
1794             @ViewDebug.IntToString(from = Gravity.START,            to = "START"),
1795             @ViewDebug.IntToString(from = Gravity.END,             to = "END"),
1796             @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL,   to = "CENTER_VERTICAL"),
1797             @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL,     to = "FILL_VERTICAL"),
1798             @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
1799             @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL,   to = "FILL_HORIZONTAL"),
1800             @ViewDebug.IntToString(from = Gravity.CENTER,            to = "CENTER"),
1801             @ViewDebug.IntToString(from = Gravity.FILL,              to = "FILL")
1802         })
1803         public int gravity = -1;
1804 
1805         /**
1806          * {@inheritDoc}
1807          */
LayoutParams(Context c, AttributeSet attrs)1808         public LayoutParams(Context c, AttributeSet attrs) {
1809             super(c, attrs);
1810             TypedArray a =
1811                     c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout_Layout);
1812 
1813             weight = a.getFloat(com.android.internal.R.styleable.LinearLayout_Layout_layout_weight, 0);
1814             gravity = a.getInt(com.android.internal.R.styleable.LinearLayout_Layout_layout_gravity, -1);
1815 
1816             a.recycle();
1817         }
1818 
1819         /**
1820          * {@inheritDoc}
1821          */
LayoutParams(int width, int height)1822         public LayoutParams(int width, int height) {
1823             super(width, height);
1824             weight = 0;
1825         }
1826 
1827         /**
1828          * Creates a new set of layout parameters with the specified width, height
1829          * and weight.
1830          *
1831          * @param width the width, either {@link #MATCH_PARENT},
1832          *        {@link #WRAP_CONTENT} or a fixed size in pixels
1833          * @param height the height, either {@link #MATCH_PARENT},
1834          *        {@link #WRAP_CONTENT} or a fixed size in pixels
1835          * @param weight the weight
1836          */
LayoutParams(int width, int height, float weight)1837         public LayoutParams(int width, int height, float weight) {
1838             super(width, height);
1839             this.weight = weight;
1840         }
1841 
1842         /**
1843          * {@inheritDoc}
1844          */
LayoutParams(ViewGroup.LayoutParams p)1845         public LayoutParams(ViewGroup.LayoutParams p) {
1846             super(p);
1847         }
1848 
1849         /**
1850          * {@inheritDoc}
1851          */
LayoutParams(MarginLayoutParams source)1852         public LayoutParams(MarginLayoutParams source) {
1853             super(source);
1854         }
1855 
1856         @Override
debug(String output)1857         public String debug(String output) {
1858             return output + "LinearLayout.LayoutParams={width=" + sizeToString(width) +
1859                     ", height=" + sizeToString(height) + " weight=" + weight +  "}";
1860         }
1861     }
1862 }
1863