• 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 android.content.Context;
20 import android.content.res.TypedArray;
21 import android.util.AttributeSet;
22 import android.view.Gravity;
23 import android.view.View;
24 import android.view.ViewDebug;
25 import android.view.ViewGroup;
26 import android.widget.RemoteViews.RemoteView;
27 
28 import com.android.internal.R;
29 
30 
31 /**
32  * A Layout that arranges its children in a single column or a single row. The direction of
33  * the row can be set by calling {@link #setOrientation(int) setOrientation()}.
34  * You can also specify gravity, which specifies the alignment of all the child elements by
35  * calling {@link #setGravity(int) setGravity()} or specify that specific children
36  * grow to fill up any remaining space in the layout by setting the <em>weight</em> member of
37  * {@link android.widget.LinearLayout.LayoutParams LinearLayout.LayoutParams}.
38  * The default orientation is horizontal.
39  *
40  * <p>
41  * Also see {@link LinearLayout.LayoutParams android.widget.LinearLayout.LayoutParams}
42  * for layout attributes </p>
43  */
44 @RemoteView
45 public class LinearLayout extends ViewGroup {
46     public static final int HORIZONTAL = 0;
47     public static final int VERTICAL = 1;
48 
49     /**
50      * Whether the children of this layout are baseline aligned.  Only applicable
51      * if {@link #mOrientation} is horizontal.
52      */
53     private boolean mBaselineAligned = true;
54 
55     /**
56      * If this layout is part of another layout that is baseline aligned,
57      * use the child at this index as the baseline.
58      *
59      * Note: this is orthogonal to {@link #mBaselineAligned}, which is concerned
60      * with whether the children of this layout are baseline aligned.
61      */
62     private int mBaselineAlignedChildIndex = -1;
63 
64     /**
65      * The additional offset to the child's baseline.
66      * We'll calculate the baseline of this layout as we measure vertically; for
67      * horizontal linear layouts, the offset of 0 is appropriate.
68      */
69     private int mBaselineChildTop = 0;
70 
71     private int mOrientation;
72     private int mGravity = Gravity.LEFT | Gravity.TOP;
73     private int mTotalLength;
74 
75     private float mWeightSum;
76 
77     private int[] mMaxAscent;
78     private int[] mMaxDescent;
79 
80     private static final int VERTICAL_GRAVITY_COUNT = 4;
81 
82     private static final int INDEX_CENTER_VERTICAL = 0;
83     private static final int INDEX_TOP = 1;
84     private static final int INDEX_BOTTOM = 2;
85     private static final int INDEX_FILL = 3;
86 
LinearLayout(Context context)87     public LinearLayout(Context context) {
88         super(context);
89     }
90 
LinearLayout(Context context, AttributeSet attrs)91     public LinearLayout(Context context, AttributeSet attrs) {
92         super(context, attrs);
93 
94         TypedArray a =
95             context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout);
96 
97         int index = a.getInt(com.android.internal.R.styleable.LinearLayout_orientation, -1);
98         if (index >= 0) {
99             setOrientation(index);
100         }
101 
102         index = a.getInt(com.android.internal.R.styleable.LinearLayout_gravity, -1);
103         if (index >= 0) {
104             setGravity(index);
105         }
106 
107         boolean baselineAligned = a.getBoolean(R.styleable.LinearLayout_baselineAligned, true);
108         if (!baselineAligned) {
109             setBaselineAligned(baselineAligned);
110         }
111 
112         mWeightSum = a.getFloat(R.styleable.LinearLayout_weightSum, -1.0f);
113 
114         mBaselineAlignedChildIndex =
115                 a.getInt(com.android.internal.R.styleable.LinearLayout_baselineAlignedChildIndex, -1);
116 
117         a.recycle();
118     }
119 
120     /**
121      * <p>Indicates whether widgets contained within this layout are aligned
122      * on their baseline or not.</p>
123      *
124      * @return true when widgets are baseline-aligned, false otherwise
125      */
isBaselineAligned()126     public boolean isBaselineAligned() {
127         return mBaselineAligned;
128     }
129 
130     /**
131      * <p>Defines whether widgets contained in this layout are
132      * baseline-aligned or not.</p>
133      *
134      * @param baselineAligned true to align widgets on their baseline,
135      *         false otherwise
136      *
137      * @attr ref android.R.styleable#LinearLayout_baselineAligned
138      */
139     @android.view.RemotableViewMethod
setBaselineAligned(boolean baselineAligned)140     public void setBaselineAligned(boolean baselineAligned) {
141         mBaselineAligned = baselineAligned;
142     }
143 
144     @Override
getBaseline()145     public int getBaseline() {
146         if (mBaselineAlignedChildIndex < 0) {
147             return super.getBaseline();
148         }
149 
150         if (getChildCount() <= mBaselineAlignedChildIndex) {
151             throw new RuntimeException("mBaselineAlignedChildIndex of LinearLayout "
152                     + "set to an index that is out of bounds.");
153         }
154 
155         final View child = getChildAt(mBaselineAlignedChildIndex);
156         final int childBaseline = child.getBaseline();
157 
158         if (childBaseline == -1) {
159             if (mBaselineAlignedChildIndex == 0) {
160                 // this is just the default case, safe to return -1
161                 return -1;
162             }
163             // the user picked an index that points to something that doesn't
164             // know how to calculate its baseline.
165             throw new RuntimeException("mBaselineAlignedChildIndex of LinearLayout "
166                     + "points to a View that doesn't know how to get its baseline.");
167         }
168 
169         // TODO: This should try to take into account the virtual offsets
170         // (See getNextLocationOffset and getLocationOffset)
171         // We should add to childTop:
172         // sum([getNextLocationOffset(getChildAt(i)) / i < mBaselineAlignedChildIndex])
173         // and also add:
174         // getLocationOffset(child)
175         int childTop = mBaselineChildTop;
176 
177         if (mOrientation == VERTICAL) {
178             final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
179             if (majorGravity != Gravity.TOP) {
180                switch (majorGravity) {
181                    case Gravity.BOTTOM:
182                        childTop = mBottom - mTop - mPaddingBottom - mTotalLength;
183                        break;
184 
185                    case Gravity.CENTER_VERTICAL:
186                        childTop += ((mBottom - mTop - mPaddingTop - mPaddingBottom) -
187                                mTotalLength) / 2;
188                        break;
189                }
190             }
191         }
192 
193         LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
194         return childTop + lp.topMargin + childBaseline;
195     }
196 
197     /**
198      * @return The index of the child that will be used if this layout is
199      *   part of a larger layout that is baseline aligned, or -1 if none has
200      *   been set.
201      */
getBaselineAlignedChildIndex()202     public int getBaselineAlignedChildIndex() {
203         return mBaselineAlignedChildIndex;
204     }
205 
206     /**
207      * @param i The index of the child that will be used if this layout is
208      *          part of a larger layout that is baseline aligned.
209      *
210      * @attr ref android.R.styleable#LinearLayout_baselineAlignedChildIndex
211      */
212     @android.view.RemotableViewMethod
setBaselineAlignedChildIndex(int i)213     public void setBaselineAlignedChildIndex(int i) {
214         if ((i < 0) || (i >= getChildCount())) {
215             throw new IllegalArgumentException("base aligned child index out "
216                     + "of range (0, " + getChildCount() + ")");
217         }
218         mBaselineAlignedChildIndex = i;
219     }
220 
221     /**
222      * <p>Returns the view at the specified index. This method can be overriden
223      * to take into account virtual children. Refer to
224      * {@link android.widget.TableLayout} and {@link android.widget.TableRow}
225      * for an example.</p>
226      *
227      * @param index the child's index
228      * @return the child at the specified index
229      */
getVirtualChildAt(int index)230     View getVirtualChildAt(int index) {
231         return getChildAt(index);
232     }
233 
234     /**
235      * <p>Returns the virtual number of children. This number might be different
236      * than the actual number of children if the layout can hold virtual
237      * children. Refer to
238      * {@link android.widget.TableLayout} and {@link android.widget.TableRow}
239      * for an example.</p>
240      *
241      * @return the virtual number of children
242      */
getVirtualChildCount()243     int getVirtualChildCount() {
244         return getChildCount();
245     }
246 
247     /**
248      * Returns the desired weights sum.
249      *
250      * @return A number greater than 0.0f if the weight sum is defined, or
251      *         a number lower than or equals to 0.0f if not weight sum is
252      *         to be used.
253      */
getWeightSum()254     public float getWeightSum() {
255         return mWeightSum;
256     }
257 
258     /**
259      * Defines the desired weights sum. If unspecified the weights sum is computed
260      * at layout time by adding the layout_weight of each child.
261      *
262      * This can be used for instance to give a single child 50% of the total
263      * available space by giving it a layout_weight of 0.5 and setting the
264      * weightSum to 1.0.
265      *
266      * @param weightSum a number greater than 0.0f, or a number lower than or equals
267      *        to 0.0f if the weight sum should be computed from the children's
268      *        layout_weight
269      */
270     @android.view.RemotableViewMethod
setWeightSum(float weightSum)271     public void setWeightSum(float weightSum) {
272         mWeightSum = Math.max(0.0f, weightSum);
273     }
274 
275     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)276     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
277         if (mOrientation == VERTICAL) {
278             measureVertical(widthMeasureSpec, heightMeasureSpec);
279         } else {
280             measureHorizontal(widthMeasureSpec, heightMeasureSpec);
281         }
282     }
283 
284     /**
285      * Measures the children when the orientation of this LinearLayout is set
286      * to {@link #VERTICAL}.
287      *
288      * @param widthMeasureSpec Horizontal space requirements as imposed by the parent.
289      * @param heightMeasureSpec Vertical space requirements as imposed by the parent.
290      *
291      * @see #getOrientation()
292      * @see #setOrientation(int)
293      * @see #onMeasure(int, int)
294      */
measureVertical(int widthMeasureSpec, int heightMeasureSpec)295     void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
296         mTotalLength = 0;
297         int maxWidth = 0;
298         int alternativeMaxWidth = 0;
299         int weightedMaxWidth = 0;
300         boolean allFillParent = true;
301         float totalWeight = 0;
302 
303         final int count = getVirtualChildCount();
304 
305         final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
306         final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
307 
308         boolean matchWidth = false;
309 
310         final int baselineChildIndex = mBaselineAlignedChildIndex;
311 
312         // See how tall everyone is. Also remember max width.
313         for (int i = 0; i < count; ++i) {
314             final View child = getVirtualChildAt(i);
315 
316             if (child == null) {
317                 mTotalLength += measureNullChild(i);
318                 continue;
319             }
320 
321             if (child.getVisibility() == View.GONE) {
322                i += getChildrenSkipCount(child, i);
323                continue;
324             }
325 
326             LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
327 
328             totalWeight += lp.weight;
329 
330             if (heightMode == MeasureSpec.EXACTLY && lp.height == 0 && lp.weight > 0) {
331                 // Optimization: don't bother measuring children who are going to use
332                 // leftover space. These views will get measured again down below if
333                 // there is any leftover space.
334                 mTotalLength += lp.topMargin + lp.bottomMargin;
335             } else {
336                int oldHeight = Integer.MIN_VALUE;
337 
338                if (lp.height == 0 && lp.weight > 0) {
339                    // heightMode is either UNSPECIFIED OR AT_MOST, and this child
340                    // wanted to stretch to fill available space. Translate that to
341                    // WRAP_CONTENT so that it does not end up with a height of 0
342                    oldHeight = 0;
343                    lp.height = LayoutParams.WRAP_CONTENT;
344                }
345 
346                // Determine how big this child would like to.  If this or
347                // previous children have given a weight, then we allow it to
348                // use all available space (and we will shrink things later
349                // if needed).
350                measureChildBeforeLayout(
351                        child, i, widthMeasureSpec, 0, heightMeasureSpec,
352                        totalWeight == 0 ? mTotalLength : 0);
353 
354                if (oldHeight != Integer.MIN_VALUE) {
355                    lp.height = oldHeight;
356                }
357 
358                mTotalLength += child.getMeasuredHeight() + lp.topMargin +
359                        lp.bottomMargin + getNextLocationOffset(child);
360             }
361 
362             /**
363              * If applicable, compute the additional offset to the child's baseline
364              * we'll need later when asked {@link #getBaseline}.
365              */
366             if ((baselineChildIndex >= 0) && (baselineChildIndex == i + 1)) {
367                mBaselineChildTop = mTotalLength;
368             }
369 
370             // if we are trying to use a child index for our baseline, the above
371             // book keeping only works if there are no children above it with
372             // weight.  fail fast to aid the developer.
373             if (i < baselineChildIndex && lp.weight > 0) {
374                 throw new RuntimeException("A child of LinearLayout with index "
375                         + "less than mBaselineAlignedChildIndex has weight > 0, which "
376                         + "won't work.  Either remove the weight, or don't set "
377                         + "mBaselineAlignedChildIndex.");
378             }
379 
380             boolean matchWidthLocally = false;
381             if (widthMode != MeasureSpec.EXACTLY && lp.width == LayoutParams.FILL_PARENT) {
382                 // The width of the linear layout will scale, and at least one
383                 // child said it wanted to match our width. Set a flag
384                 // indicating that we need to remeasure at least that view when
385                 // we know our width.
386                 matchWidth = true;
387                 matchWidthLocally = true;
388             }
389 
390             final int margin = lp.leftMargin + lp.rightMargin;
391             final int measuredWidth = child.getMeasuredWidth() + margin;
392             maxWidth = Math.max(maxWidth, measuredWidth);
393 
394             allFillParent = allFillParent && lp.width == LayoutParams.FILL_PARENT;
395             if (lp.weight > 0) {
396                 /*
397                  * Widths of weighted Views are bogus if we end up
398                  * remeasuring, so keep them separate.
399                  */
400                 weightedMaxWidth = Math.max(weightedMaxWidth,
401                         matchWidthLocally ? margin : measuredWidth);
402             } else {
403                 alternativeMaxWidth = Math.max(alternativeMaxWidth,
404                         matchWidthLocally ? margin : measuredWidth);
405             }
406 
407             i += getChildrenSkipCount(child, i);
408         }
409 
410         // Add in our padding
411         mTotalLength += mPaddingTop + mPaddingBottom;
412 
413         int heightSize = mTotalLength;
414 
415         // Check against our minimum height
416         heightSize = Math.max(heightSize, getSuggestedMinimumHeight());
417 
418         // Reconcile our calculated size with the heightMeasureSpec
419         heightSize = resolveSize(heightSize, heightMeasureSpec);
420 
421         // Either expand children with weight to take up available space or
422         // shrink them if they extend beyond our current bounds
423         int delta = heightSize - mTotalLength;
424         if (delta != 0 && totalWeight > 0.0f) {
425             float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
426 
427             mTotalLength = 0;
428 
429             for (int i = 0; i < count; ++i) {
430                 final View child = getVirtualChildAt(i);
431 
432                 if (child.getVisibility() == View.GONE) {
433                     continue;
434                 }
435 
436                 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
437 
438                 float childExtra = lp.weight;
439                 if (childExtra > 0) {
440                     // Child said it could absorb extra space -- give him his share
441                     int share = (int) (childExtra * delta / weightSum);
442                     weightSum -= childExtra;
443                     delta -= share;
444 
445                     final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
446                             mPaddingLeft + mPaddingRight +
447                                     lp.leftMargin + lp.rightMargin, lp.width);
448 
449                     // TODO: Use a field like lp.isMeasured to figure out if this
450                     // child has been previously measured
451                     if ((lp.height != 0) || (heightMode != MeasureSpec.EXACTLY)) {
452                         // child was measured once already above...
453                         // base new measurement on stored values
454                         int childHeight = child.getMeasuredHeight() + share;
455                         if (childHeight < 0) {
456                             childHeight = 0;
457                         }
458 
459                         child.measure(childWidthMeasureSpec,
460                                 MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY));
461                     } else {
462                         // child was skipped in the loop above.
463                         // Measure for this first time here
464                         child.measure(childWidthMeasureSpec,
465                                 MeasureSpec.makeMeasureSpec(share > 0 ? share : 0,
466                                         MeasureSpec.EXACTLY));
467                     }
468                 }
469 
470                 final int margin =  lp.leftMargin + lp.rightMargin;
471                 final int measuredWidth = child.getMeasuredWidth() + margin;
472                 maxWidth = Math.max(maxWidth, measuredWidth);
473 
474                 boolean matchWidthLocally = widthMode != MeasureSpec.EXACTLY &&
475                         lp.width == LayoutParams.FILL_PARENT;
476 
477                 alternativeMaxWidth = Math.max(alternativeMaxWidth,
478                         matchWidthLocally ? margin : measuredWidth);
479 
480                 allFillParent = allFillParent && lp.width == LayoutParams.FILL_PARENT;
481 
482                 mTotalLength += child.getMeasuredHeight() + lp.topMargin +
483                         lp.bottomMargin + getNextLocationOffset(child);
484             }
485 
486             // Add in our padding
487             mTotalLength += mPaddingTop + mPaddingBottom;
488         } else {
489             alternativeMaxWidth = Math.max(alternativeMaxWidth,
490                                            weightedMaxWidth);
491         }
492 
493         if (!allFillParent && widthMode != MeasureSpec.EXACTLY) {
494             maxWidth = alternativeMaxWidth;
495         }
496 
497         maxWidth += mPaddingLeft + mPaddingRight;
498 
499         // Check against our minimum width
500         maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
501 
502         setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), heightSize);
503 
504         if (matchWidth) {
505             forceUniformWidth(count, heightMeasureSpec);
506         }
507     }
508 
forceUniformWidth(int count, int heightMeasureSpec)509     private void forceUniformWidth(int count, int heightMeasureSpec) {
510         // Pretend that the linear layout has an exact size.
511         int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(),
512                 MeasureSpec.EXACTLY);
513         for (int i = 0; i< count; ++i) {
514            final View child = getVirtualChildAt(i);
515            if (child.getVisibility() != GONE) {
516                LinearLayout.LayoutParams lp = ((LinearLayout.LayoutParams)child.getLayoutParams());
517 
518                if (lp.width == LayoutParams.FILL_PARENT) {
519                    // Temporarily force children to reuse their old measured height
520                    // FIXME: this may not be right for something like wrapping text?
521                    int oldHeight = lp.height;
522                    lp.height = child.getMeasuredHeight();
523 
524                    // Remeasue with new dimensions
525                    measureChildWithMargins(child, uniformMeasureSpec, 0, heightMeasureSpec, 0);
526                    lp.height = oldHeight;
527                }
528            }
529         }
530     }
531 
532     /**
533      * Measures the children when the orientation of this LinearLayout is set
534      * to {@link #HORIZONTAL}.
535      *
536      * @param widthMeasureSpec Horizontal space requirements as imposed by the parent.
537      * @param heightMeasureSpec Vertical space requirements as imposed by the parent.
538      *
539      * @see #getOrientation()
540      * @see #setOrientation(int)
541      * @see #onMeasure(int, int)
542      */
measureHorizontal(int widthMeasureSpec, int heightMeasureSpec)543     void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec) {
544         mTotalLength = 0;
545         int maxHeight = 0;
546         int alternativeMaxHeight = 0;
547         int weightedMaxHeight = 0;
548         boolean allFillParent = true;
549         float totalWeight = 0;
550 
551         final int count = getVirtualChildCount();
552 
553         final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
554         final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
555 
556         boolean matchHeight = false;
557 
558         if (mMaxAscent == null || mMaxDescent == null) {
559             mMaxAscent = new int[VERTICAL_GRAVITY_COUNT];
560             mMaxDescent = new int[VERTICAL_GRAVITY_COUNT];
561         }
562 
563         final int[] maxAscent = mMaxAscent;
564         final int[] maxDescent = mMaxDescent;
565 
566         maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
567         maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;
568 
569         final boolean baselineAligned = mBaselineAligned;
570 
571         // See how wide everyone is. Also remember max height.
572         for (int i = 0; i < count; ++i) {
573             final View child = getVirtualChildAt(i);
574 
575             if (child == null) {
576                 mTotalLength += measureNullChild(i);
577                 continue;
578             }
579 
580             if (child.getVisibility() == GONE) {
581                 i += getChildrenSkipCount(child, i);
582                 continue;
583             }
584 
585             final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
586 
587             totalWeight += lp.weight;
588 
589             if (widthMode == MeasureSpec.EXACTLY && lp.width == 0 && lp.weight > 0) {
590                 // Optimization: don't bother measuring children who are going to use
591                 // leftover space. These views will get measured again down below if
592                 // there is any leftover space.
593                 mTotalLength += lp.leftMargin + lp.rightMargin;
594 
595                 // Baseline alignment requires to measure widgets to obtain the
596                 // baseline offset (in particular for TextViews).
597                 // The following defeats the optimization mentioned above.
598                 // Allow the child to use as much space as it wants because we
599                 // can shrink things later (and re-measure).
600                 if (baselineAligned) {
601                     final int freeSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
602                     child.measure(freeSpec, freeSpec);
603                 }
604             } else {
605                 int oldWidth = Integer.MIN_VALUE;
606 
607                 if (lp.width == 0 && lp.weight > 0) {
608                     // widthMode is either UNSPECIFIED OR AT_MOST, and this child
609                     // wanted to stretch to fill available space. Translate that to
610                     // WRAP_CONTENT so that it does not end up with a width of 0
611                     oldWidth = 0;
612                     lp.width = LayoutParams.WRAP_CONTENT;
613                 }
614 
615                 // Determine how big this child would like to be. If this or
616                 // previous children have given a weight, then we allow it to
617                 // use all available space (and we will shrink things later
618                 // if needed).
619                 measureChildBeforeLayout(child, i, widthMeasureSpec,
620                         totalWeight == 0 ? mTotalLength : 0,
621                         heightMeasureSpec, 0);
622 
623                 if (oldWidth != Integer.MIN_VALUE) {
624                     lp.width = oldWidth;
625                 }
626 
627                 mTotalLength += child.getMeasuredWidth() + lp.leftMargin +
628                         lp.rightMargin + getNextLocationOffset(child);
629             }
630 
631             boolean matchHeightLocally = false;
632             if (heightMode != MeasureSpec.EXACTLY && lp.height == LayoutParams.FILL_PARENT) {
633                 // The height of the linear layout will scale, and at least one
634                 // child said it wanted to match our height. Set a flag indicating that
635                 // we need to remeasure at least that view when we know our height.
636                 matchHeight = true;
637                 matchHeightLocally = true;
638             }
639 
640             final int margin = lp.topMargin + lp.bottomMargin;
641             final int childHeight = child.getMeasuredHeight() + margin;
642 
643             if (baselineAligned) {
644                 final int childBaseline = child.getBaseline();
645                 if (childBaseline != -1) {
646                     // Translates the child's vertical gravity into an index
647                     // in the range 0..VERTICAL_GRAVITY_COUNT
648                     final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity)
649                             & Gravity.VERTICAL_GRAVITY_MASK;
650                     final int index = ((gravity >> Gravity.AXIS_Y_SHIFT)
651                             & ~Gravity.AXIS_SPECIFIED) >> 1;
652 
653                     maxAscent[index] = Math.max(maxAscent[index], childBaseline);
654                     maxDescent[index] = Math.max(maxDescent[index], childHeight - childBaseline);
655                 }
656             }
657 
658             maxHeight = Math.max(maxHeight, childHeight);
659 
660             allFillParent = allFillParent && lp.height == LayoutParams.FILL_PARENT;
661             if (lp.weight > 0) {
662                 /*
663                  * Heights of weighted Views are bogus if we end up
664                  * remeasuring, so keep them separate.
665                  */
666                 weightedMaxHeight = Math.max(weightedMaxHeight,
667                         matchHeightLocally ? margin : childHeight);
668             } else {
669                 alternativeMaxHeight = Math.max(alternativeMaxHeight,
670                         matchHeightLocally ? margin : childHeight);
671             }
672 
673             i += getChildrenSkipCount(child, i);
674         }
675 
676         // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP,
677         // the most common case
678         if (maxAscent[INDEX_TOP] != -1 ||
679                 maxAscent[INDEX_CENTER_VERTICAL] != -1 ||
680                 maxAscent[INDEX_BOTTOM] != -1 ||
681                 maxAscent[INDEX_FILL] != -1) {
682             final int ascent = Math.max(maxAscent[INDEX_FILL],
683                     Math.max(maxAscent[INDEX_CENTER_VERTICAL],
684                     Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM])));
685             final int descent = Math.max(maxDescent[INDEX_FILL],
686                     Math.max(maxDescent[INDEX_CENTER_VERTICAL],
687                     Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM])));
688             maxHeight = Math.max(maxHeight, ascent + descent);
689         }
690 
691         // Add in our padding
692         mTotalLength += mPaddingLeft + mPaddingRight;
693 
694         int widthSize = mTotalLength;
695 
696         // Check against our minimum width
697         widthSize = Math.max(widthSize, getSuggestedMinimumWidth());
698 
699         // Reconcile our calculated size with the widthMeasureSpec
700         widthSize = resolveSize(widthSize, widthMeasureSpec);
701 
702         // Either expand children with weight to take up available space or
703         // shrink them if they extend beyond our current bounds
704         int delta = widthSize - mTotalLength;
705         if (delta != 0 && totalWeight > 0.0f) {
706             float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
707 
708             maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
709             maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;
710             maxHeight = -1;
711 
712             mTotalLength = 0;
713 
714             for (int i = 0; i < count; ++i) {
715                 final View child = getVirtualChildAt(i);
716 
717                 if (child == null || child.getVisibility() == View.GONE) {
718                     continue;
719                 }
720 
721                 final LinearLayout.LayoutParams lp =
722                         (LinearLayout.LayoutParams) child.getLayoutParams();
723 
724                 float childExtra = lp.weight;
725                 if (childExtra > 0) {
726                     // Child said it could absorb extra space -- give him his share
727                     int share = (int) (childExtra * delta / weightSum);
728                     weightSum -= childExtra;
729                     delta -= share;
730 
731                     final int childHeightMeasureSpec = getChildMeasureSpec(
732                             heightMeasureSpec,
733                             mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin,
734                             lp.height);
735 
736                     // TODO: Use a field like lp.isMeasured to figure out if this
737                     // child has been previously measured
738                     if ((lp.width != 0) || (widthMode != MeasureSpec.EXACTLY)) {
739                         // child was measured once already above ... base new measurement
740                         // on stored values
741                         int childWidth = child.getMeasuredWidth() + share;
742                         if (childWidth < 0) {
743                             childWidth = 0;
744                         }
745 
746                         child.measure(
747                             MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
748                             childHeightMeasureSpec);
749                     } else {
750                         // child was skipped in the loop above. Measure for this first time here
751                         child.measure(MeasureSpec.makeMeasureSpec(
752                                 share > 0 ? share : 0, MeasureSpec.EXACTLY),
753                                 childHeightMeasureSpec);
754                     }
755                 }
756 
757                 mTotalLength += child.getMeasuredWidth() + lp.leftMargin +
758                         lp.rightMargin + getNextLocationOffset(child);
759 
760                 boolean matchHeightLocally = heightMode != MeasureSpec.EXACTLY &&
761                         lp.height == LayoutParams.FILL_PARENT;
762 
763                 final int margin = lp.topMargin + lp .bottomMargin;
764                 int childHeight = child.getMeasuredHeight() + margin;
765                 maxHeight = Math.max(maxHeight, childHeight);
766                 alternativeMaxHeight = Math.max(alternativeMaxHeight,
767                         matchHeightLocally ? margin : childHeight);
768 
769                 allFillParent = allFillParent && lp.height == LayoutParams.FILL_PARENT;
770 
771                 if (baselineAligned) {
772                     final int childBaseline = child.getBaseline();
773                     if (childBaseline != -1) {
774                         // Translates the child's vertical gravity into an index in the range 0..2
775                         final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity)
776                                 & Gravity.VERTICAL_GRAVITY_MASK;
777                         final int index = ((gravity >> Gravity.AXIS_Y_SHIFT)
778                                 & ~Gravity.AXIS_SPECIFIED) >> 1;
779 
780                         maxAscent[index] = Math.max(maxAscent[index], childBaseline);
781                         maxDescent[index] = Math.max(maxDescent[index],
782                                 childHeight - childBaseline);
783                     }
784                 }
785             }
786 
787             // Add in our padding
788             mTotalLength += mPaddingLeft + mPaddingRight;
789 
790             // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP,
791             // the most common case
792             if (maxAscent[INDEX_TOP] != -1 ||
793                     maxAscent[INDEX_CENTER_VERTICAL] != -1 ||
794                     maxAscent[INDEX_BOTTOM] != -1 ||
795                     maxAscent[INDEX_FILL] != -1) {
796                 final int ascent = Math.max(maxAscent[INDEX_FILL],
797                         Math.max(maxAscent[INDEX_CENTER_VERTICAL],
798                         Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM])));
799                 final int descent = Math.max(maxDescent[INDEX_FILL],
800                         Math.max(maxDescent[INDEX_CENTER_VERTICAL],
801                         Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM])));
802                 maxHeight = Math.max(maxHeight, ascent + descent);
803             }
804         } else {
805             alternativeMaxHeight = Math.max(alternativeMaxHeight, weightedMaxHeight);
806         }
807 
808         if (!allFillParent && heightMode != MeasureSpec.EXACTLY) {
809             maxHeight = alternativeMaxHeight;
810         }
811 
812         maxHeight += mPaddingTop + mPaddingBottom;
813 
814         // Check against our minimum height
815         maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
816 
817         setMeasuredDimension(widthSize, resolveSize(maxHeight, heightMeasureSpec));
818 
819         if (matchHeight) {
820             forceUniformHeight(count, widthMeasureSpec);
821         }
822     }
823 
forceUniformHeight(int count, int widthMeasureSpec)824     private void forceUniformHeight(int count, int widthMeasureSpec) {
825         // Pretend that the linear layout has an exact size. This is the measured height of
826         // ourselves. The measured height should be the max height of the children, changed
827         // to accomodate the heightMesureSpec from the parent
828         int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(),
829                 MeasureSpec.EXACTLY);
830         for (int i = 0; i < count; ++i) {
831            final View child = getVirtualChildAt(i);
832            if (child.getVisibility() != GONE) {
833                LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
834 
835                if (lp.height == LayoutParams.FILL_PARENT) {
836                    // Temporarily force children to reuse their old measured width
837                    // FIXME: this may not be right for something like wrapping text?
838                    int oldWidth = lp.width;
839                    lp.width = child.getMeasuredWidth();
840 
841                    // Remeasure with new dimensions
842                    measureChildWithMargins(child, widthMeasureSpec, 0, uniformMeasureSpec, 0);
843                    lp.width = oldWidth;
844                }
845            }
846         }
847     }
848 
849     /**
850      * <p>Returns the number of children to skip after measuring/laying out
851      * the specified child.</p>
852      *
853      * @param child the child after which we want to skip children
854      * @param index the index of the child after which we want to skip children
855      * @return the number of children to skip, 0 by default
856      */
getChildrenSkipCount(View child, int index)857     int getChildrenSkipCount(View child, int index) {
858         return 0;
859     }
860 
861     /**
862      * <p>Returns the size (width or height) that should be occupied by a null
863      * child.</p>
864      *
865      * @param childIndex the index of the null child
866      * @return the width or height of the child depending on the orientation
867      */
measureNullChild(int childIndex)868     int measureNullChild(int childIndex) {
869         return 0;
870     }
871 
872     /**
873      * <p>Measure the child according to the parent's measure specs. This
874      * method should be overriden by subclasses to force the sizing of
875      * children. This method is called by {@link #measureVertical(int, int)} and
876      * {@link #measureHorizontal(int, int)}.</p>
877      *
878      * @param child the child to measure
879      * @param childIndex the index of the child in this view
880      * @param widthMeasureSpec horizontal space requirements as imposed by the parent
881      * @param totalWidth extra space that has been used up by the parent horizontally
882      * @param heightMeasureSpec vertical space requirements as imposed by the parent
883      * @param totalHeight extra space that has been used up by the parent vertically
884      */
measureChildBeforeLayout(View child, int childIndex, int widthMeasureSpec, int totalWidth, int heightMeasureSpec, int totalHeight)885     void measureChildBeforeLayout(View child, int childIndex,
886             int widthMeasureSpec, int totalWidth, int heightMeasureSpec,
887             int totalHeight) {
888         measureChildWithMargins(child, widthMeasureSpec, totalWidth,
889                 heightMeasureSpec, totalHeight);
890     }
891 
892     /**
893      * <p>Return the location offset of the specified child. This can be used
894      * by subclasses to change the location of a given widget.</p>
895      *
896      * @param child the child for which to obtain the location offset
897      * @return the location offset in pixels
898      */
getLocationOffset(View child)899     int getLocationOffset(View child) {
900         return 0;
901     }
902 
903     /**
904      * <p>Return the size offset of the next sibling of the specified child.
905      * This can be used by subclasses to change the location of the widget
906      * following <code>child</code>.</p>
907      *
908      * @param child the child whose next sibling will be moved
909      * @return the location offset of the next child in pixels
910      */
getNextLocationOffset(View child)911     int getNextLocationOffset(View child) {
912         return 0;
913     }
914 
915     @Override
onLayout(boolean changed, int l, int t, int r, int b)916     protected void onLayout(boolean changed, int l, int t, int r, int b) {
917         if (mOrientation == VERTICAL) {
918             layoutVertical();
919         } else {
920             layoutHorizontal();
921         }
922     }
923 
924     /**
925      * Position the children during a layout pass if the orientation of this
926      * LinearLayout is set to {@link #VERTICAL}.
927      *
928      * @see #getOrientation()
929      * @see #setOrientation(int)
930      * @see #onLayout(boolean, int, int, int, int)
931      */
layoutVertical()932     void layoutVertical() {
933         final int paddingLeft = mPaddingLeft;
934 
935         int childTop = mPaddingTop;
936         int childLeft = paddingLeft;
937 
938         // Where right end of child should go
939         final int width = mRight - mLeft;
940         int childRight = width - mPaddingRight;
941 
942         // Space available for child
943         int childSpace = width - paddingLeft - mPaddingRight;
944 
945         final int count = getVirtualChildCount();
946 
947         final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
948         final int minorGravity = mGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
949 
950         if (majorGravity != Gravity.TOP) {
951            switch (majorGravity) {
952                case Gravity.BOTTOM:
953                    // mTotalLength contains the padding already, we add the top
954                    // padding to compensate
955                    childTop = mBottom - mTop + mPaddingTop - mTotalLength;
956                    break;
957 
958                case Gravity.CENTER_VERTICAL:
959                    childTop += ((mBottom - mTop)  - mTotalLength) / 2;
960                    break;
961            }
962 
963         }
964 
965         for (int i = 0; i < count; i++) {
966             final View child = getVirtualChildAt(i);
967             if (child == null) {
968                 childTop += measureNullChild(i);
969             } else if (child.getVisibility() != GONE) {
970                 final int childWidth = child.getMeasuredWidth();
971                 final int childHeight = child.getMeasuredHeight();
972 
973                 final LinearLayout.LayoutParams lp =
974                         (LinearLayout.LayoutParams) child.getLayoutParams();
975 
976                 int gravity = lp.gravity;
977                 if (gravity < 0) {
978                     gravity = minorGravity;
979                 }
980 
981                 switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
982                     case Gravity.LEFT:
983                         childLeft = paddingLeft + lp.leftMargin;
984                         break;
985 
986                     case Gravity.CENTER_HORIZONTAL:
987                         childLeft = paddingLeft + ((childSpace - childWidth) / 2)
988                                 + lp.leftMargin - lp.rightMargin;
989                         break;
990 
991                     case Gravity.RIGHT:
992                         childLeft = childRight - childWidth - lp.rightMargin;
993                         break;
994                 }
995 
996 
997                 childTop += lp.topMargin;
998                 setChildFrame(child, childLeft, childTop + getLocationOffset(child),
999                         childWidth, childHeight);
1000                 childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);
1001 
1002                 i += getChildrenSkipCount(child, i);
1003             }
1004         }
1005     }
1006 
1007     /**
1008      * Position the children during a layout pass if the orientation of this
1009      * LinearLayout is set to {@link #HORIZONTAL}.
1010      *
1011      * @see #getOrientation()
1012      * @see #setOrientation(int)
1013      * @see #onLayout(boolean, int, int, int, int)
1014      */
layoutHorizontal()1015     void layoutHorizontal() {
1016         final int paddingTop = mPaddingTop;
1017 
1018         int childTop = paddingTop;
1019         int childLeft = mPaddingLeft;
1020 
1021         // Where bottom of child should go
1022         final int height = mBottom - mTop;
1023         int childBottom = height - mPaddingBottom;
1024 
1025         // Space available for child
1026         int childSpace = height - paddingTop - mPaddingBottom;
1027 
1028         final int count = getVirtualChildCount();
1029 
1030         final int majorGravity = mGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
1031         final int minorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
1032 
1033         final boolean baselineAligned = mBaselineAligned;
1034 
1035         final int[] maxAscent = mMaxAscent;
1036         final int[] maxDescent = mMaxDescent;
1037 
1038         if (majorGravity != Gravity.LEFT) {
1039             switch (majorGravity) {
1040                 case Gravity.RIGHT:
1041                     // mTotalLength contains the padding already, we add the left
1042                     // padding to compensate
1043                     childLeft = mRight - mLeft + mPaddingLeft - mTotalLength;
1044                     break;
1045 
1046                 case Gravity.CENTER_HORIZONTAL:
1047                     childLeft += ((mRight - mLeft) - mTotalLength) / 2;
1048                     break;
1049             }
1050        }
1051 
1052         for (int i = 0; i < count; i++) {
1053             final View child = getVirtualChildAt(i);
1054 
1055             if (child == null) {
1056                 childLeft += measureNullChild(i);
1057             } else if (child.getVisibility() != GONE) {
1058                 final int childWidth = child.getMeasuredWidth();
1059                 final int childHeight = child.getMeasuredHeight();
1060                 int childBaseline = -1;
1061 
1062                 final LinearLayout.LayoutParams lp =
1063                         (LinearLayout.LayoutParams) child.getLayoutParams();
1064 
1065                 if (baselineAligned && lp.height != LayoutParams.FILL_PARENT) {
1066                     childBaseline = child.getBaseline();
1067                 }
1068 
1069                 int gravity = lp.gravity;
1070                 if (gravity < 0) {
1071                     gravity = minorGravity;
1072                 }
1073 
1074                 switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
1075                     case Gravity.TOP:
1076                         childTop = paddingTop + lp.topMargin;
1077                         if (childBaseline != -1) {
1078                             childTop += maxAscent[INDEX_TOP] - childBaseline;
1079                         }
1080                         break;
1081 
1082                     case Gravity.CENTER_VERTICAL:
1083                         // Removed support for baselign alignment when layout_gravity or
1084                         // gravity == center_vertical. See bug #1038483.
1085                         // Keep the code around if we need to re-enable this feature
1086                         // if (childBaseline != -1) {
1087                         //     // Align baselines vertically only if the child is smaller than us
1088                         //     if (childSpace - childHeight > 0) {
1089                         //         childTop = paddingTop + (childSpace / 2) - childBaseline;
1090                         //     } else {
1091                         //         childTop = paddingTop + (childSpace - childHeight) / 2;
1092                         //     }
1093                         // } else {
1094                         childTop = paddingTop + ((childSpace - childHeight) / 2)
1095                                 + lp.topMargin - lp.bottomMargin;
1096                         break;
1097 
1098                     case Gravity.BOTTOM:
1099                         childTop = childBottom - childHeight - lp.bottomMargin;
1100                         if (childBaseline != -1) {
1101                             int descent = child.getMeasuredHeight() - childBaseline;
1102                             childTop -= (maxDescent[INDEX_BOTTOM] - descent);
1103                         }
1104                         break;
1105                 }
1106 
1107                 childLeft += lp.leftMargin;
1108                 setChildFrame(child, childLeft + getLocationOffset(child), childTop,
1109                         childWidth, childHeight);
1110                 childLeft += childWidth + lp.rightMargin +
1111                         getNextLocationOffset(child);
1112 
1113                 i += getChildrenSkipCount(child, i);
1114             }
1115         }
1116     }
1117 
setChildFrame(View child, int left, int top, int width, int height)1118     private void setChildFrame(View child, int left, int top, int width, int height) {
1119         child.layout(left, top, left + width, top + height);
1120     }
1121 
1122     /**
1123      * Should the layout be a column or a row.
1124      * @param orientation Pass HORIZONTAL or VERTICAL. Default
1125      * value is HORIZONTAL.
1126      *
1127      * @attr ref android.R.styleable#LinearLayout_orientation
1128      */
setOrientation(int orientation)1129     public void setOrientation(int orientation) {
1130         if (mOrientation != orientation) {
1131             mOrientation = orientation;
1132             requestLayout();
1133         }
1134     }
1135 
1136     /**
1137      * Returns the current orientation.
1138      *
1139      * @return either {@link #HORIZONTAL} or {@link #VERTICAL}
1140      */
getOrientation()1141     public int getOrientation() {
1142         return mOrientation;
1143     }
1144 
1145     /**
1146      * Describes how the child views are positioned. Defaults to GRAVITY_TOP. If
1147      * this layout has a VERTICAL orientation, this controls where all the child
1148      * views are placed if there is extra vertical space. If this layout has a
1149      * HORIZONTAL orientation, this controls the alignment of the children.
1150      *
1151      * @param gravity See {@link android.view.Gravity}
1152      *
1153      * @attr ref android.R.styleable#LinearLayout_gravity
1154      */
1155     @android.view.RemotableViewMethod
setGravity(int gravity)1156     public void setGravity(int gravity) {
1157         if (mGravity != gravity) {
1158             if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) {
1159                 gravity |= Gravity.LEFT;
1160             }
1161 
1162             if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
1163                 gravity |= Gravity.TOP;
1164             }
1165 
1166             mGravity = gravity;
1167             requestLayout();
1168         }
1169     }
1170 
1171     @android.view.RemotableViewMethod
setHorizontalGravity(int horizontalGravity)1172     public void setHorizontalGravity(int horizontalGravity) {
1173         final int gravity = horizontalGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
1174         if ((mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != gravity) {
1175             mGravity = (mGravity & ~Gravity.HORIZONTAL_GRAVITY_MASK) | gravity;
1176             requestLayout();
1177         }
1178     }
1179 
1180     @android.view.RemotableViewMethod
setVerticalGravity(int verticalGravity)1181     public void setVerticalGravity(int verticalGravity) {
1182         final int gravity = verticalGravity & Gravity.VERTICAL_GRAVITY_MASK;
1183         if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != gravity) {
1184             mGravity = (mGravity & ~Gravity.VERTICAL_GRAVITY_MASK) | gravity;
1185             requestLayout();
1186         }
1187     }
1188 
1189     @Override
generateLayoutParams(AttributeSet attrs)1190     public LayoutParams generateLayoutParams(AttributeSet attrs) {
1191         return new LinearLayout.LayoutParams(getContext(), attrs);
1192     }
1193 
1194     /**
1195      * Returns a set of layout parameters with a width of
1196      * {@link android.view.ViewGroup.LayoutParams#FILL_PARENT}
1197      * and a height of {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}
1198      * when the layout's orientation is {@link #VERTICAL}. When the orientation is
1199      * {@link #HORIZONTAL}, the width is set to {@link LayoutParams#WRAP_CONTENT}
1200      * and the height to {@link LayoutParams#WRAP_CONTENT}.
1201      */
1202     @Override
generateDefaultLayoutParams()1203     protected LayoutParams generateDefaultLayoutParams() {
1204         if (mOrientation == HORIZONTAL) {
1205             return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
1206         } else if (mOrientation == VERTICAL) {
1207             return new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
1208         }
1209         return null;
1210     }
1211 
1212     @Override
generateLayoutParams(ViewGroup.LayoutParams p)1213     protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
1214         return new LayoutParams(p);
1215     }
1216 
1217 
1218     // Override to allow type-checking of LayoutParams.
1219     @Override
checkLayoutParams(ViewGroup.LayoutParams p)1220     protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
1221         return p instanceof LinearLayout.LayoutParams;
1222     }
1223 
1224     /**
1225      * Per-child layout information associated with ViewLinearLayout.
1226      *
1227      * @attr ref android.R.styleable#LinearLayout_Layout_layout_weight
1228      * @attr ref android.R.styleable#LinearLayout_Layout_layout_gravity
1229      */
1230     public static class LayoutParams extends ViewGroup.MarginLayoutParams {
1231         /**
1232          * Indicates how much of the extra space in the LinearLayout will be
1233          * allocated to the view associated with these LayoutParams. Specify
1234          * 0 if the view should not be stretched. Otherwise the extra pixels
1235          * will be pro-rated among all views whose weight is greater than 0.
1236          */
1237         @ViewDebug.ExportedProperty
1238         public float weight;
1239 
1240         /**
1241          * Gravity for the view associated with these LayoutParams.
1242          *
1243          * @see android.view.Gravity
1244          */
1245         @ViewDebug.ExportedProperty(mapping = {
1246             @ViewDebug.IntToString(from =  -1,                       to = "NONE"),
1247             @ViewDebug.IntToString(from = Gravity.NO_GRAVITY,        to = "NONE"),
1248             @ViewDebug.IntToString(from = Gravity.TOP,               to = "TOP"),
1249             @ViewDebug.IntToString(from = Gravity.BOTTOM,            to = "BOTTOM"),
1250             @ViewDebug.IntToString(from = Gravity.LEFT,              to = "LEFT"),
1251             @ViewDebug.IntToString(from = Gravity.RIGHT,             to = "RIGHT"),
1252             @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL,   to = "CENTER_VERTICAL"),
1253             @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL,     to = "FILL_VERTICAL"),
1254             @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
1255             @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL,   to = "FILL_HORIZONTAL"),
1256             @ViewDebug.IntToString(from = Gravity.CENTER,            to = "CENTER"),
1257             @ViewDebug.IntToString(from = Gravity.FILL,              to = "FILL")
1258         })
1259         public int gravity = -1;
1260 
1261         /**
1262          * {@inheritDoc}
1263          */
LayoutParams(Context c, AttributeSet attrs)1264         public LayoutParams(Context c, AttributeSet attrs) {
1265             super(c, attrs);
1266             TypedArray a =
1267                     c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout_Layout);
1268 
1269             weight = a.getFloat(com.android.internal.R.styleable.LinearLayout_Layout_layout_weight, 0);
1270             gravity = a.getInt(com.android.internal.R.styleable.LinearLayout_Layout_layout_gravity, -1);
1271 
1272             a.recycle();
1273         }
1274 
1275         /**
1276          * {@inheritDoc}
1277          */
LayoutParams(int width, int height)1278         public LayoutParams(int width, int height) {
1279             super(width, height);
1280             weight = 0;
1281         }
1282 
1283         /**
1284          * Creates a new set of layout parameters with the specified width, height
1285          * and weight.
1286          *
1287          * @param width the width, either {@link #FILL_PARENT},
1288          *        {@link #WRAP_CONTENT} or a fixed size in pixels
1289          * @param height the height, either {@link #FILL_PARENT},
1290          *        {@link #WRAP_CONTENT} or a fixed size in pixels
1291          * @param weight the weight
1292          */
LayoutParams(int width, int height, float weight)1293         public LayoutParams(int width, int height, float weight) {
1294             super(width, height);
1295             this.weight = weight;
1296         }
1297 
1298         /**
1299          * {@inheritDoc}
1300          */
LayoutParams(ViewGroup.LayoutParams p)1301         public LayoutParams(ViewGroup.LayoutParams p) {
1302             super(p);
1303         }
1304 
1305         /**
1306          * {@inheritDoc}
1307          */
LayoutParams(MarginLayoutParams source)1308         public LayoutParams(MarginLayoutParams source) {
1309             super(source);
1310         }
1311 
1312         @Override
debug(String output)1313         public String debug(String output) {
1314             return output + "LinearLayout.LayoutParams={width=" + sizeToString(width) +
1315                     ", height=" + sizeToString(height) + " weight=" + weight +  "}";
1316         }
1317     }
1318 }
1319