blob: e0ef86c26b2b38a6a49f4d6da7aadae930a44307 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package android.widget;
18
Gilles Debunnef5c6eff2010-02-09 19:08:36 -080019import com.android.internal.R;
20
Tor Norbyed9273d62013-05-30 15:59:53 -070021import android.annotation.IntDef;
Siva Velusamy94a6d152015-05-05 15:07:00 -070022import android.annotation.NonNull;
Scott Kennedy3a1fa102015-03-05 19:15:11 -080023import android.annotation.Nullable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.content.Context;
25import android.content.res.TypedArray;
Adam Powellfcca00a2010-11-30 21:26:29 -080026import android.graphics.Canvas;
27import android.graphics.drawable.Drawable;
Alan Viverette40e1df32015-08-25 16:50:27 -040028import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.util.AttributeSet;
30import android.view.Gravity;
31import android.view.View;
32import android.view.ViewDebug;
33import android.view.ViewGroup;
Siva Velusamy94a6d152015-05-05 15:07:00 -070034import android.view.ViewHierarchyEncoder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.widget.RemoteViews.RemoteView;
36
Tor Norbyed9273d62013-05-30 15:59:53 -070037import java.lang.annotation.Retention;
38import java.lang.annotation.RetentionPolicy;
39
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040
41/**
42 * A Layout that arranges its children in a single column or a single row. The direction of
43 * the row can be set by calling {@link #setOrientation(int) setOrientation()}.
44 * You can also specify gravity, which specifies the alignment of all the child elements by
45 * calling {@link #setGravity(int) setGravity()} or specify that specific children
46 * grow to fill up any remaining space in the layout by setting the <em>weight</em> member of
47 * {@link android.widget.LinearLayout.LayoutParams LinearLayout.LayoutParams}.
48 * The default orientation is horizontal.
49 *
Scott Main4c359b72012-07-24 15:51:27 -070050 * <p>See the <a href="{@docRoot}guide/topics/ui/layout/linear.html">Linear Layout</a>
51 * guide.</p>
Scott Main41ec6532010-08-19 16:57:07 -070052 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053 * <p>
54 * Also see {@link LinearLayout.LayoutParams android.widget.LinearLayout.LayoutParams}
55 * for layout attributes </p>
Romain Guy9295ada2010-06-15 11:33:24 -070056 *
57 * @attr ref android.R.styleable#LinearLayout_baselineAligned
58 * @attr ref android.R.styleable#LinearLayout_baselineAlignedChildIndex
59 * @attr ref android.R.styleable#LinearLayout_gravity
60 * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
61 * @attr ref android.R.styleable#LinearLayout_orientation
62 * @attr ref android.R.styleable#LinearLayout_weightSum
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063 */
64@RemoteView
65public class LinearLayout extends ViewGroup {
Tor Norbyed9273d62013-05-30 15:59:53 -070066 /** @hide */
67 @IntDef({HORIZONTAL, VERTICAL})
68 @Retention(RetentionPolicy.SOURCE)
69 public @interface OrientationMode {}
70
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071 public static final int HORIZONTAL = 0;
72 public static final int VERTICAL = 1;
73
Tor Norbyed9273d62013-05-30 15:59:53 -070074 /** @hide */
75 @IntDef(flag = true,
76 value = {
77 SHOW_DIVIDER_NONE,
78 SHOW_DIVIDER_BEGINNING,
79 SHOW_DIVIDER_MIDDLE,
80 SHOW_DIVIDER_END
81 })
82 @Retention(RetentionPolicy.SOURCE)
83 public @interface DividerMode {}
84
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085 /**
Adam Powellfcca00a2010-11-30 21:26:29 -080086 * Don't show any dividers.
87 */
88 public static final int SHOW_DIVIDER_NONE = 0;
89 /**
90 * Show a divider at the beginning of the group.
91 */
92 public static final int SHOW_DIVIDER_BEGINNING = 1;
93 /**
94 * Show dividers between each item in the group.
95 */
96 public static final int SHOW_DIVIDER_MIDDLE = 2;
97 /**
98 * Show a divider at the end of the group.
99 */
100 public static final int SHOW_DIVIDER_END = 4;
101
102 /**
Alan Viverette40e1df32015-08-25 16:50:27 -0400103 * Compatibility check. Old versions of the platform would give different
104 * results from measurement passes using EXACTLY and non-EXACTLY modes,
105 * even when the resulting size was the same.
106 */
107 private final boolean mAllowInconsistentMeasurement;
108
109 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 * Whether the children of this layout are baseline aligned. Only applicable
111 * if {@link #mOrientation} is horizontal.
112 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700113 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 private boolean mBaselineAligned = true;
115
116 /**
117 * If this layout is part of another layout that is baseline aligned,
118 * use the child at this index as the baseline.
119 *
120 * Note: this is orthogonal to {@link #mBaselineAligned}, which is concerned
121 * with whether the children of this layout are baseline aligned.
122 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700123 @ViewDebug.ExportedProperty(category = "layout")
Karl Rosaenc1f9c402009-08-12 17:18:33 -0700124 private int mBaselineAlignedChildIndex = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125
126 /**
127 * The additional offset to the child's baseline.
128 * We'll calculate the baseline of this layout as we measure vertically; for
129 * horizontal linear layouts, the offset of 0 is appropriate.
130 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700131 @ViewDebug.ExportedProperty(category = "measurement")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132 private int mBaselineChildTop = 0;
133
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700134 @ViewDebug.ExportedProperty(category = "measurement")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 private int mOrientation;
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700136
Fabrice Di Megliobce84d22011-06-02 15:57:01 -0700137 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = {
138 @ViewDebug.FlagToString(mask = -1,
139 equals = -1, name = "NONE"),
140 @ViewDebug.FlagToString(mask = Gravity.NO_GRAVITY,
141 equals = Gravity.NO_GRAVITY,name = "NONE"),
142 @ViewDebug.FlagToString(mask = Gravity.TOP,
143 equals = Gravity.TOP, name = "TOP"),
144 @ViewDebug.FlagToString(mask = Gravity.BOTTOM,
145 equals = Gravity.BOTTOM, name = "BOTTOM"),
146 @ViewDebug.FlagToString(mask = Gravity.LEFT,
147 equals = Gravity.LEFT, name = "LEFT"),
148 @ViewDebug.FlagToString(mask = Gravity.RIGHT,
149 equals = Gravity.RIGHT, name = "RIGHT"),
Fabrice Di Meglio9e3b0022011-06-06 16:30:29 -0700150 @ViewDebug.FlagToString(mask = Gravity.START,
151 equals = Gravity.START, name = "START"),
152 @ViewDebug.FlagToString(mask = Gravity.END,
153 equals = Gravity.END, name = "END"),
Fabrice Di Megliobce84d22011-06-02 15:57:01 -0700154 @ViewDebug.FlagToString(mask = Gravity.CENTER_VERTICAL,
155 equals = Gravity.CENTER_VERTICAL, name = "CENTER_VERTICAL"),
156 @ViewDebug.FlagToString(mask = Gravity.FILL_VERTICAL,
157 equals = Gravity.FILL_VERTICAL, name = "FILL_VERTICAL"),
158 @ViewDebug.FlagToString(mask = Gravity.CENTER_HORIZONTAL,
159 equals = Gravity.CENTER_HORIZONTAL, name = "CENTER_HORIZONTAL"),
160 @ViewDebug.FlagToString(mask = Gravity.FILL_HORIZONTAL,
161 equals = Gravity.FILL_HORIZONTAL, name = "FILL_HORIZONTAL"),
162 @ViewDebug.FlagToString(mask = Gravity.CENTER,
163 equals = Gravity.CENTER, name = "CENTER"),
164 @ViewDebug.FlagToString(mask = Gravity.FILL,
165 equals = Gravity.FILL, name = "FILL"),
Fabrice Di Meglioc46f7ff2011-06-06 18:23:10 -0700166 @ViewDebug.FlagToString(mask = Gravity.RELATIVE_LAYOUT_DIRECTION,
167 equals = Gravity.RELATIVE_LAYOUT_DIRECTION, name = "RELATIVE")
Jon Miranda4597e982014-07-29 07:25:49 -0700168 }, formatToHexString = true)
Fabrice Di Meglio9e3b0022011-06-06 16:30:29 -0700169 private int mGravity = Gravity.START | Gravity.TOP;
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700170
171 @ViewDebug.ExportedProperty(category = "measurement")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 private int mTotalLength;
173
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700174 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 private float mWeightSum;
176
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700177 @ViewDebug.ExportedProperty(category = "layout")
Romain Guy5b1b2412010-01-21 19:09:51 -0800178 private boolean mUseLargestChild;
179
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 private int[] mMaxAscent;
181 private int[] mMaxDescent;
182
183 private static final int VERTICAL_GRAVITY_COUNT = 4;
184
185 private static final int INDEX_CENTER_VERTICAL = 0;
186 private static final int INDEX_TOP = 1;
187 private static final int INDEX_BOTTOM = 2;
Romain Guy5b1b2412010-01-21 19:09:51 -0800188 private static final int INDEX_FILL = 3;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189
Adam Powellfcca00a2010-11-30 21:26:29 -0800190 private Drawable mDivider;
191 private int mDividerWidth;
192 private int mDividerHeight;
193 private int mShowDividers;
194 private int mDividerPadding;
195
Selim Cinek78528b22015-06-02 17:33:09 +0200196 private int mLayoutDirection = View.LAYOUT_DIRECTION_UNDEFINED;
197
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 public LinearLayout(Context context) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700199 this(context, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 }
201
Scott Kennedy3a1fa102015-03-05 19:15:11 -0800202 public LinearLayout(Context context, @Nullable AttributeSet attrs) {
Romain Guy9295ada2010-06-15 11:33:24 -0700203 this(context, attrs, 0);
204 }
205
Scott Kennedy3a1fa102015-03-05 19:15:11 -0800206 public LinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
Alan Viverette617feb92013-09-09 18:09:13 -0700207 this(context, attrs, defStyleAttr, 0);
208 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209
Alan Viverette617feb92013-09-09 18:09:13 -0700210 public LinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
211 super(context, attrs, defStyleAttr, defStyleRes);
212
213 final TypedArray a = context.obtainStyledAttributes(
214 attrs, com.android.internal.R.styleable.LinearLayout, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215
216 int index = a.getInt(com.android.internal.R.styleable.LinearLayout_orientation, -1);
217 if (index >= 0) {
218 setOrientation(index);
219 }
220
221 index = a.getInt(com.android.internal.R.styleable.LinearLayout_gravity, -1);
222 if (index >= 0) {
223 setGravity(index);
224 }
225
226 boolean baselineAligned = a.getBoolean(R.styleable.LinearLayout_baselineAligned, true);
227 if (!baselineAligned) {
228 setBaselineAligned(baselineAligned);
229 }
230
231 mWeightSum = a.getFloat(R.styleable.LinearLayout_weightSum, -1.0f);
232
233 mBaselineAlignedChildIndex =
234 a.getInt(com.android.internal.R.styleable.LinearLayout_baselineAlignedChildIndex, -1);
235
Romain Guy9295ada2010-06-15 11:33:24 -0700236 mUseLargestChild = a.getBoolean(R.styleable.LinearLayout_measureWithLargestChild, false);
Romain Guy5b1b2412010-01-21 19:09:51 -0800237
Adam Powellfcca00a2010-11-30 21:26:29 -0800238 setDividerDrawable(a.getDrawable(R.styleable.LinearLayout_divider));
239 mShowDividers = a.getInt(R.styleable.LinearLayout_showDividers, SHOW_DIVIDER_NONE);
240 mDividerPadding = a.getDimensionPixelSize(R.styleable.LinearLayout_dividerPadding, 0);
241
Alan Viverette40e1df32015-08-25 16:50:27 -0400242 final int version = context.getApplicationInfo().targetSdkVersion;
243 mAllowInconsistentMeasurement = version <= Build.VERSION_CODES.M;
244
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245 a.recycle();
246 }
247
248 /**
Adam Powellfcca00a2010-11-30 21:26:29 -0800249 * Set how dividers should be shown between items in this layout
250 *
251 * @param showDividers One or more of {@link #SHOW_DIVIDER_BEGINNING},
252 * {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END},
253 * or {@link #SHOW_DIVIDER_NONE} to show no dividers.
254 */
Tor Norbyed9273d62013-05-30 15:59:53 -0700255 public void setShowDividers(@DividerMode int showDividers) {
Adam Powellfcca00a2010-11-30 21:26:29 -0800256 if (showDividers != mShowDividers) {
257 requestLayout();
258 }
259 mShowDividers = showDividers;
260 }
261
Patrick Dubroye0a799a2011-05-04 16:19:22 -0700262 @Override
263 public boolean shouldDelayChildPressedState() {
264 return false;
265 }
266
Adam Powellfcca00a2010-11-30 21:26:29 -0800267 /**
268 * @return A flag set indicating how dividers should be shown around items.
269 * @see #setShowDividers(int)
270 */
Tor Norbyed9273d62013-05-30 15:59:53 -0700271 @DividerMode
Adam Powellfcca00a2010-11-30 21:26:29 -0800272 public int getShowDividers() {
273 return mShowDividers;
274 }
275
276 /**
Philip Milne1018fb42012-03-13 12:00:04 -0700277 * @return the divider Drawable that will divide each item.
278 *
279 * @see #setDividerDrawable(Drawable)
280 *
281 * @attr ref android.R.styleable#LinearLayout_divider
282 */
283 public Drawable getDividerDrawable() {
284 return mDivider;
285 }
286
287 /**
Adam Powellfcca00a2010-11-30 21:26:29 -0800288 * Set a drawable to be used as a divider between items.
Philip Milne1018fb42012-03-13 12:00:04 -0700289 *
Adam Powellfcca00a2010-11-30 21:26:29 -0800290 * @param divider Drawable that will divide each item.
Philip Milne1018fb42012-03-13 12:00:04 -0700291 *
Adam Powellfcca00a2010-11-30 21:26:29 -0800292 * @see #setShowDividers(int)
Philip Milne1018fb42012-03-13 12:00:04 -0700293 *
294 * @attr ref android.R.styleable#LinearLayout_divider
Adam Powellfcca00a2010-11-30 21:26:29 -0800295 */
296 public void setDividerDrawable(Drawable divider) {
297 if (divider == mDivider) {
298 return;
299 }
300 mDivider = divider;
301 if (divider != null) {
302 mDividerWidth = divider.getIntrinsicWidth();
303 mDividerHeight = divider.getIntrinsicHeight();
304 } else {
305 mDividerWidth = 0;
306 mDividerHeight = 0;
307 }
308 setWillNotDraw(divider == null);
309 requestLayout();
310 }
311
Adam Powell696cba52011-03-29 10:38:16 -0700312 /**
313 * Set padding displayed on both ends of dividers.
314 *
315 * @param padding Padding value in pixels that will be applied to each end
316 *
317 * @see #setShowDividers(int)
318 * @see #setDividerDrawable(Drawable)
319 * @see #getDividerPadding()
320 */
321 public void setDividerPadding(int padding) {
322 mDividerPadding = padding;
323 }
324
325 /**
326 * Get the padding size used to inset dividers in pixels
327 *
328 * @see #setShowDividers(int)
329 * @see #setDividerDrawable(Drawable)
330 * @see #setDividerPadding(int)
331 */
332 public int getDividerPadding() {
333 return mDividerPadding;
334 }
335
Adam Powell640a66e2011-04-29 10:18:53 -0700336 /**
337 * Get the width of the current divider drawable.
338 *
339 * @hide Used internally by framework.
340 */
341 public int getDividerWidth() {
342 return mDividerWidth;
343 }
344
Adam Powellfcca00a2010-11-30 21:26:29 -0800345 @Override
346 protected void onDraw(Canvas canvas) {
347 if (mDivider == null) {
348 return;
349 }
350
351 if (mOrientation == VERTICAL) {
352 drawDividersVertical(canvas);
353 } else {
354 drawDividersHorizontal(canvas);
355 }
356 }
357
358 void drawDividersVertical(Canvas canvas) {
Adam Powellfcca00a2010-11-30 21:26:29 -0800359 final int count = getVirtualChildCount();
Adam Powellfcca00a2010-11-30 21:26:29 -0800360 for (int i = 0; i < count; i++) {
361 final View child = getVirtualChildAt(i);
Adam Powell35aecd52011-07-01 13:43:49 -0700362 if (child != null && child.getVisibility() != GONE) {
Adam Powell696cba52011-03-29 10:38:16 -0700363 if (hasDividerBeforeChildAt(i)) {
Adam Powell35aecd52011-07-01 13:43:49 -0700364 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Vladimir Baryshnikov20761fc2012-01-17 14:59:48 -0800365 final int top = child.getTop() - lp.topMargin - mDividerHeight;
Adam Powellfcca00a2010-11-30 21:26:29 -0800366 drawHorizontalDivider(canvas, top);
Adam Powellfcca00a2010-11-30 21:26:29 -0800367 }
Adam Powellfcca00a2010-11-30 21:26:29 -0800368 }
369 }
370
Adam Powell696cba52011-03-29 10:38:16 -0700371 if (hasDividerBeforeChildAt(count)) {
Doris Liuec6a4cd2015-06-25 15:16:54 -0700372 final View child = getLastNonGoneChild();
Adam Powell35aecd52011-07-01 13:43:49 -0700373 int bottom = 0;
374 if (child == null) {
375 bottom = getHeight() - getPaddingBottom() - mDividerHeight;
376 } else {
377 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
378 bottom = child.getBottom() + lp.bottomMargin;
379 }
380 drawHorizontalDivider(canvas, bottom);
Adam Powellfcca00a2010-11-30 21:26:29 -0800381 }
382 }
383
Doris Liuec6a4cd2015-06-25 15:16:54 -0700384 /**
385 * Finds the last child that is not gone. The last child will be used as the reference for
386 * where the end divider should be drawn.
387 */
388 private View getLastNonGoneChild() {
389 for (int i = getVirtualChildCount() - 1; i >= 0; i--) {
Alan Viverettead526932015-12-17 12:42:39 -0500390 final View child = getVirtualChildAt(i);
Doris Liuec6a4cd2015-06-25 15:16:54 -0700391 if (child != null && child.getVisibility() != GONE) {
392 return child;
393 }
394 }
395 return null;
396 }
397
Adam Powellfcca00a2010-11-30 21:26:29 -0800398 void drawDividersHorizontal(Canvas canvas) {
Adam Powellfcca00a2010-11-30 21:26:29 -0800399 final int count = getVirtualChildCount();
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700400 final boolean isLayoutRtl = isLayoutRtl();
Adam Powellfcca00a2010-11-30 21:26:29 -0800401 for (int i = 0; i < count; i++) {
402 final View child = getVirtualChildAt(i);
Adam Powell35aecd52011-07-01 13:43:49 -0700403 if (child != null && child.getVisibility() != GONE) {
Adam Powell696cba52011-03-29 10:38:16 -0700404 if (hasDividerBeforeChildAt(i)) {
Adam Powell35aecd52011-07-01 13:43:49 -0700405 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700406 final int position;
407 if (isLayoutRtl) {
408 position = child.getRight() + lp.rightMargin;
409 } else {
410 position = child.getLeft() - lp.leftMargin - mDividerWidth;
411 }
412 drawVerticalDivider(canvas, position);
Adam Powellfcca00a2010-11-30 21:26:29 -0800413 }
Adam Powellfcca00a2010-11-30 21:26:29 -0800414 }
415 }
416
Adam Powell696cba52011-03-29 10:38:16 -0700417 if (hasDividerBeforeChildAt(count)) {
Doris Liuec6a4cd2015-06-25 15:16:54 -0700418 final View child = getLastNonGoneChild();
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700419 int position;
Adam Powell35aecd52011-07-01 13:43:49 -0700420 if (child == null) {
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700421 if (isLayoutRtl) {
422 position = getPaddingLeft();
423 } else {
424 position = getWidth() - getPaddingRight() - mDividerWidth;
425 }
Adam Powell35aecd52011-07-01 13:43:49 -0700426 } else {
427 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700428 if (isLayoutRtl) {
429 position = child.getLeft() - lp.leftMargin - mDividerWidth;
430 } else {
431 position = child.getRight() + lp.rightMargin;
432 }
Adam Powell35aecd52011-07-01 13:43:49 -0700433 }
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700434 drawVerticalDivider(canvas, position);
Adam Powellfcca00a2010-11-30 21:26:29 -0800435 }
436 }
437
438 void drawHorizontalDivider(Canvas canvas, int top) {
439 mDivider.setBounds(getPaddingLeft() + mDividerPadding, top,
440 getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);
441 mDivider.draw(canvas);
442 }
443
444 void drawVerticalDivider(Canvas canvas, int left) {
445 mDivider.setBounds(left, getPaddingTop() + mDividerPadding,
446 left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding);
447 mDivider.draw(canvas);
448 }
449
450 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451 * <p>Indicates whether widgets contained within this layout are aligned
452 * on their baseline or not.</p>
453 *
454 * @return true when widgets are baseline-aligned, false otherwise
455 */
456 public boolean isBaselineAligned() {
457 return mBaselineAligned;
458 }
459
460 /**
461 * <p>Defines whether widgets contained in this layout are
462 * baseline-aligned or not.</p>
463 *
464 * @param baselineAligned true to align widgets on their baseline,
465 * false otherwise
466 *
467 * @attr ref android.R.styleable#LinearLayout_baselineAligned
468 */
469 @android.view.RemotableViewMethod
470 public void setBaselineAligned(boolean baselineAligned) {
471 mBaselineAligned = baselineAligned;
472 }
473
Romain Guy9295ada2010-06-15 11:33:24 -0700474 /**
475 * When true, all children with a weight will be considered having
476 * the minimum size of the largest child. If false, all children are
477 * measured normally.
478 *
479 * @return True to measure children with a weight using the minimum
480 * size of the largest child, false otherwise.
Philip Milne1018fb42012-03-13 12:00:04 -0700481 *
482 * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
Romain Guy9295ada2010-06-15 11:33:24 -0700483 */
484 public boolean isMeasureWithLargestChildEnabled() {
485 return mUseLargestChild;
486 }
487
488 /**
489 * When set to true, all children with a weight will be considered having
490 * the minimum size of the largest child. If false, all children are
491 * measured normally.
492 *
493 * Disabled by default.
494 *
495 * @param enabled True to measure children with a weight using the
496 * minimum size of the largest child, false otherwise.
Philip Milne1018fb42012-03-13 12:00:04 -0700497 *
498 * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
Romain Guy9295ada2010-06-15 11:33:24 -0700499 */
500 @android.view.RemotableViewMethod
501 public void setMeasureWithLargestChildEnabled(boolean enabled) {
502 mUseLargestChild = enabled;
503 }
504
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 @Override
506 public int getBaseline() {
507 if (mBaselineAlignedChildIndex < 0) {
508 return super.getBaseline();
509 }
510
511 if (getChildCount() <= mBaselineAlignedChildIndex) {
512 throw new RuntimeException("mBaselineAlignedChildIndex of LinearLayout "
513 + "set to an index that is out of bounds.");
514 }
515
516 final View child = getChildAt(mBaselineAlignedChildIndex);
517 final int childBaseline = child.getBaseline();
518
519 if (childBaseline == -1) {
520 if (mBaselineAlignedChildIndex == 0) {
521 // this is just the default case, safe to return -1
522 return -1;
523 }
524 // the user picked an index that points to something that doesn't
525 // know how to calculate its baseline.
526 throw new RuntimeException("mBaselineAlignedChildIndex of LinearLayout "
527 + "points to a View that doesn't know how to get its baseline.");
528 }
529
530 // TODO: This should try to take into account the virtual offsets
531 // (See getNextLocationOffset and getLocationOffset)
532 // We should add to childTop:
533 // sum([getNextLocationOffset(getChildAt(i)) / i < mBaselineAlignedChildIndex])
534 // and also add:
535 // getLocationOffset(child)
536 int childTop = mBaselineChildTop;
537
538 if (mOrientation == VERTICAL) {
539 final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
540 if (majorGravity != Gravity.TOP) {
541 switch (majorGravity) {
542 case Gravity.BOTTOM:
543 childTop = mBottom - mTop - mPaddingBottom - mTotalLength;
544 break;
545
546 case Gravity.CENTER_VERTICAL:
547 childTop += ((mBottom - mTop - mPaddingTop - mPaddingBottom) -
548 mTotalLength) / 2;
549 break;
550 }
551 }
552 }
553
554 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
555 return childTop + lp.topMargin + childBaseline;
556 }
557
558 /**
559 * @return The index of the child that will be used if this layout is
560 * part of a larger layout that is baseline aligned, or -1 if none has
561 * been set.
562 */
563 public int getBaselineAlignedChildIndex() {
564 return mBaselineAlignedChildIndex;
565 }
566
567 /**
568 * @param i The index of the child that will be used if this layout is
569 * part of a larger layout that is baseline aligned.
570 *
571 * @attr ref android.R.styleable#LinearLayout_baselineAlignedChildIndex
572 */
573 @android.view.RemotableViewMethod
574 public void setBaselineAlignedChildIndex(int i) {
575 if ((i < 0) || (i >= getChildCount())) {
576 throw new IllegalArgumentException("base aligned child index out "
577 + "of range (0, " + getChildCount() + ")");
578 }
579 mBaselineAlignedChildIndex = i;
580 }
581
582 /**
583 * <p>Returns the view at the specified index. This method can be overriden
584 * to take into account virtual children. Refer to
585 * {@link android.widget.TableLayout} and {@link android.widget.TableRow}
586 * for an example.</p>
587 *
588 * @param index the child's index
Alan Viverettead526932015-12-17 12:42:39 -0500589 * @return the child at the specified index, may be {@code null}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 */
Alan Viverettead526932015-12-17 12:42:39 -0500591 @Nullable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 View getVirtualChildAt(int index) {
593 return getChildAt(index);
594 }
595
596 /**
597 * <p>Returns the virtual number of children. This number might be different
598 * than the actual number of children if the layout can hold virtual
599 * children. Refer to
600 * {@link android.widget.TableLayout} and {@link android.widget.TableRow}
601 * for an example.</p>
602 *
603 * @return the virtual number of children
604 */
605 int getVirtualChildCount() {
606 return getChildCount();
607 }
608
609 /**
610 * Returns the desired weights sum.
611 *
612 * @return A number greater than 0.0f if the weight sum is defined, or
613 * a number lower than or equals to 0.0f if not weight sum is
614 * to be used.
615 */
616 public float getWeightSum() {
617 return mWeightSum;
618 }
619
620 /**
621 * Defines the desired weights sum. If unspecified the weights sum is computed
622 * at layout time by adding the layout_weight of each child.
623 *
624 * This can be used for instance to give a single child 50% of the total
625 * available space by giving it a layout_weight of 0.5 and setting the
626 * weightSum to 1.0.
627 *
628 * @param weightSum a number greater than 0.0f, or a number lower than or equals
629 * to 0.0f if the weight sum should be computed from the children's
630 * layout_weight
631 */
632 @android.view.RemotableViewMethod
633 public void setWeightSum(float weightSum) {
634 mWeightSum = Math.max(0.0f, weightSum);
635 }
636
637 @Override
638 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
639 if (mOrientation == VERTICAL) {
640 measureVertical(widthMeasureSpec, heightMeasureSpec);
641 } else {
642 measureHorizontal(widthMeasureSpec, heightMeasureSpec);
643 }
644 }
645
646 /**
Adam Powell696cba52011-03-29 10:38:16 -0700647 * Determines where to position dividers between children.
648 *
649 * @param childIndex Index of child to check for preceding divider
650 * @return true if there should be a divider before the child at childIndex
651 * @hide Pending API consideration. Currently only used internally by the system.
652 */
653 protected boolean hasDividerBeforeChildAt(int childIndex) {
Doris Liuec6a4cd2015-06-25 15:16:54 -0700654 if (childIndex == getVirtualChildCount()) {
655 // Check whether the end divider should draw.
Adam Powell696cba52011-03-29 10:38:16 -0700656 return (mShowDividers & SHOW_DIVIDER_END) != 0;
Adam Powell696cba52011-03-29 10:38:16 -0700657 }
Doris Liuec6a4cd2015-06-25 15:16:54 -0700658 boolean allViewsAreGoneBefore = allViewsAreGoneBefore(childIndex);
659 if (allViewsAreGoneBefore) {
660 // This is the first view that's not gone, check if beginning divider is enabled.
661 return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0;
662 } else {
663 return (mShowDividers & SHOW_DIVIDER_MIDDLE) != 0;
664 }
665 }
666
667 /**
668 * Checks whether all (virtual) child views before the given index are gone.
669 */
670 private boolean allViewsAreGoneBefore(int childIndex) {
671 for (int i = childIndex - 1; i >= 0; i--) {
Alan Viverettead526932015-12-17 12:42:39 -0500672 final View child = getVirtualChildAt(i);
Doris Liuf102d422015-06-30 13:42:22 -0700673 if (child != null && child.getVisibility() != GONE) {
Doris Liuec6a4cd2015-06-25 15:16:54 -0700674 return false;
675 }
676 }
677 return true;
Adam Powell696cba52011-03-29 10:38:16 -0700678 }
679
680 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681 * Measures the children when the orientation of this LinearLayout is set
682 * to {@link #VERTICAL}.
683 *
684 * @param widthMeasureSpec Horizontal space requirements as imposed by the parent.
685 * @param heightMeasureSpec Vertical space requirements as imposed by the parent.
686 *
687 * @see #getOrientation()
688 * @see #setOrientation(int)
689 * @see #onMeasure(int, int)
690 */
691 void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
692 mTotalLength = 0;
693 int maxWidth = 0;
Dianne Hackborn189ee182010-12-02 21:48:53 -0800694 int childState = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 int alternativeMaxWidth = 0;
696 int weightedMaxWidth = 0;
697 boolean allFillParent = true;
698 float totalWeight = 0;
699
700 final int count = getVirtualChildCount();
701
702 final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
703 final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
704
705 boolean matchWidth = false;
Alan Viverette65be9cc2014-02-24 18:21:09 -0800706 boolean skippedMeasure = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800707
708 final int baselineChildIndex = mBaselineAlignedChildIndex;
Romain Guy5b1b2412010-01-21 19:09:51 -0800709 final boolean useLargestChild = mUseLargestChild;
710
711 int largestChildHeight = Integer.MIN_VALUE;
Alan Viverette40e1df32015-08-25 16:50:27 -0400712 int consumedExcessSpace = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713
714 // See how tall everyone is. Also remember max width.
715 for (int i = 0; i < count; ++i) {
716 final View child = getVirtualChildAt(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717 if (child == null) {
718 mTotalLength += measureNullChild(i);
719 continue;
720 }
721
722 if (child.getVisibility() == View.GONE) {
723 i += getChildrenSkipCount(child, i);
724 continue;
725 }
726
Adam Powell696cba52011-03-29 10:38:16 -0700727 if (hasDividerBeforeChildAt(i)) {
Adam Powellfcca00a2010-11-30 21:26:29 -0800728 mTotalLength += mDividerHeight;
729 }
730
Alan Viverette40e1df32015-08-25 16:50:27 -0400731 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732
733 totalWeight += lp.weight;
Alan Viverette40e1df32015-08-25 16:50:27 -0400734
735 final boolean useExcessSpace = lp.height == 0 && lp.weight > 0;
736 if (heightMode == MeasureSpec.EXACTLY && useExcessSpace) {
737 // Optimization: don't bother measuring children who are only
738 // laid out using excess space. These views will get measured
739 // later if we have space to distribute.
Romain Guy053b4802010-02-05 15:34:33 -0800740 final int totalLength = mTotalLength;
741 mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);
Alan Viverette65be9cc2014-02-24 18:21:09 -0800742 skippedMeasure = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 } else {
Alan Viverette40e1df32015-08-25 16:50:27 -0400744 if (useExcessSpace) {
745 // The heightMode is either UNSPECIFIED or AT_MOST, and
746 // this child is only laid out using excess space. Measure
747 // using WRAP_CONTENT so that we can find out the view's
748 // optimal height. We'll restore the original height of 0
749 // after measurement.
Gilles Debunnef5c6eff2010-02-09 19:08:36 -0800750 lp.height = LayoutParams.WRAP_CONTENT;
Romain Guy5b1b2412010-01-21 19:09:51 -0800751 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752
Gilles Debunnef5c6eff2010-02-09 19:08:36 -0800753 // Determine how big this child would like to be. If this or
Romain Guy5b1b2412010-01-21 19:09:51 -0800754 // previous children have given a weight, then we allow it to
755 // use all available space (and we will shrink things later
756 // if needed).
Alan Viverette40e1df32015-08-25 16:50:27 -0400757 final int usedHeight = totalWeight == 0 ? mTotalLength : 0;
758 measureChildBeforeLayout(child, i, widthMeasureSpec, 0,
759 heightMeasureSpec, usedHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760
Alan Viverette5a969df2015-07-31 12:42:10 -0400761 final int childHeight = child.getMeasuredHeight();
Alan Viverette40e1df32015-08-25 16:50:27 -0400762 if (useExcessSpace) {
763 // Restore the original height and record how much space
764 // we've allocated to excess-only children so that we can
765 // match the behavior of EXACTLY measurement.
766 lp.height = 0;
767 consumedExcessSpace += childHeight;
768 }
769
Romain Guy053b4802010-02-05 15:34:33 -0800770 final int totalLength = mTotalLength;
771 mTotalLength = Math.max(totalLength, totalLength + childHeight + lp.topMargin +
772 lp.bottomMargin + getNextLocationOffset(child));
Romain Guy5b1b2412010-01-21 19:09:51 -0800773
774 if (useLargestChild) {
775 largestChildHeight = Math.max(childHeight, largestChildHeight);
776 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 }
778
779 /**
780 * If applicable, compute the additional offset to the child's baseline
781 * we'll need later when asked {@link #getBaseline}.
782 */
783 if ((baselineChildIndex >= 0) && (baselineChildIndex == i + 1)) {
784 mBaselineChildTop = mTotalLength;
785 }
786
787 // if we are trying to use a child index for our baseline, the above
788 // book keeping only works if there are no children above it with
789 // weight. fail fast to aid the developer.
790 if (i < baselineChildIndex && lp.weight > 0) {
791 throw new RuntimeException("A child of LinearLayout with index "
792 + "less than mBaselineAlignedChildIndex has weight > 0, which "
793 + "won't work. Either remove the weight, or don't set "
794 + "mBaselineAlignedChildIndex.");
795 }
796
797 boolean matchWidthLocally = false;
Romain Guy980a9382010-01-08 15:06:28 -0800798 if (widthMode != MeasureSpec.EXACTLY && lp.width == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 // The width of the linear layout will scale, and at least one
800 // child said it wanted to match our width. Set a flag
801 // indicating that we need to remeasure at least that view when
802 // we know our width.
803 matchWidth = true;
804 matchWidthLocally = true;
805 }
806
807 final int margin = lp.leftMargin + lp.rightMargin;
808 final int measuredWidth = child.getMeasuredWidth() + margin;
809 maxWidth = Math.max(maxWidth, measuredWidth);
Dianne Hackborn189ee182010-12-02 21:48:53 -0800810 childState = combineMeasuredStates(childState, child.getMeasuredState());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811
Romain Guy980a9382010-01-08 15:06:28 -0800812 allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813 if (lp.weight > 0) {
814 /*
815 * Widths of weighted Views are bogus if we end up
816 * remeasuring, so keep them separate.
817 */
818 weightedMaxWidth = Math.max(weightedMaxWidth,
819 matchWidthLocally ? margin : measuredWidth);
820 } else {
821 alternativeMaxWidth = Math.max(alternativeMaxWidth,
822 matchWidthLocally ? margin : measuredWidth);
823 }
824
825 i += getChildrenSkipCount(child, i);
826 }
Romain Guy5b1b2412010-01-21 19:09:51 -0800827
Adam Powell696cba52011-03-29 10:38:16 -0700828 if (mTotalLength > 0 && hasDividerBeforeChildAt(count)) {
Adam Powellfcca00a2010-11-30 21:26:29 -0800829 mTotalLength += mDividerHeight;
830 }
831
Adam Powellf8ac6b72011-05-23 18:14:09 -0700832 if (useLargestChild &&
833 (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED)) {
Romain Guy5b1b2412010-01-21 19:09:51 -0800834 mTotalLength = 0;
835
836 for (int i = 0; i < count; ++i) {
837 final View child = getVirtualChildAt(i);
Romain Guy5b1b2412010-01-21 19:09:51 -0800838 if (child == null) {
839 mTotalLength += measureNullChild(i);
840 continue;
841 }
842
843 if (child.getVisibility() == GONE) {
844 i += getChildrenSkipCount(child, i);
845 continue;
846 }
847
848 final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
849 child.getLayoutParams();
Romain Guy053b4802010-02-05 15:34:33 -0800850 // Account for negative margins
851 final int totalLength = mTotalLength;
852 mTotalLength = Math.max(totalLength, totalLength + largestChildHeight +
853 lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));
Romain Guy5b1b2412010-01-21 19:09:51 -0800854 }
855 }
856
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 // Add in our padding
858 mTotalLength += mPaddingTop + mPaddingBottom;
859
860 int heightSize = mTotalLength;
861
862 // Check against our minimum height
863 heightSize = Math.max(heightSize, getSuggestedMinimumHeight());
864
865 // Reconcile our calculated size with the heightMeasureSpec
Dianne Hackborn189ee182010-12-02 21:48:53 -0800866 int heightSizeAndState = resolveSizeAndState(heightSize, heightMeasureSpec, 0);
867 heightSize = heightSizeAndState & MEASURED_SIZE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868
869 // Either expand children with weight to take up available space or
Alan Viverette65be9cc2014-02-24 18:21:09 -0800870 // shrink them if they extend beyond our current bounds. If we skipped
871 // measurement on any children, we need to measure them now.
Alan Viverette40e1df32015-08-25 16:50:27 -0400872 final int delta = heightSize - mTotalLength
873 + (mAllowInconsistentMeasurement ? 0 : consumedExcessSpace);
Alan Viverette65be9cc2014-02-24 18:21:09 -0800874 if (skippedMeasure || delta != 0 && totalWeight > 0.0f) {
Alan Viverette40e1df32015-08-25 16:50:27 -0400875 final float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876
877 mTotalLength = 0;
878
879 for (int i = 0; i < count; ++i) {
880 final View child = getVirtualChildAt(i);
Alan Viverette40e1df32015-08-25 16:50:27 -0400881 if (child == null || child.getVisibility() == View.GONE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800882 continue;
883 }
Alan Viverette40e1df32015-08-25 16:50:27 -0400884
885 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
886 final float childExtra = lp.weight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800887 if (childExtra > 0) {
Alan Viverette40e1df32015-08-25 16:50:27 -0400888 final int share = (int) (childExtra * delta / weightSum);
889 final int childHeight;
890 if (lp.height == 0 && (!mAllowInconsistentMeasurement
891 || heightMode == MeasureSpec.EXACTLY)) {
892 // This child needs to be laid out from scratch using
893 // only its share of excess space.
894 childHeight = share;
Alan Viverette5a969df2015-07-31 12:42:10 -0400895 } else {
Alan Viverette40e1df32015-08-25 16:50:27 -0400896 // This child had some intrinsic height to which we
897 // need to add its share of excess space.
898 childHeight = child.getMeasuredHeight() + share;
Alan Viverette5a969df2015-07-31 12:42:10 -0400899 }
Dianne Hackborn189ee182010-12-02 21:48:53 -0800900
Alan Viverette40e1df32015-08-25 16:50:27 -0400901 final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
902 Math.max(0, childHeight), MeasureSpec.EXACTLY);
903 final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
904 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin,
905 lp.width);
906 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
907
Dianne Hackborn189ee182010-12-02 21:48:53 -0800908 // Child may now not fit in vertical dimension.
909 childState = combineMeasuredStates(childState, child.getMeasuredState()
910 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 }
912
913 final int margin = lp.leftMargin + lp.rightMargin;
914 final int measuredWidth = child.getMeasuredWidth() + margin;
915 maxWidth = Math.max(maxWidth, measuredWidth);
916
917 boolean matchWidthLocally = widthMode != MeasureSpec.EXACTLY &&
Romain Guy980a9382010-01-08 15:06:28 -0800918 lp.width == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800919
920 alternativeMaxWidth = Math.max(alternativeMaxWidth,
921 matchWidthLocally ? margin : measuredWidth);
922
Romain Guy980a9382010-01-08 15:06:28 -0800923 allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924
Romain Guy053b4802010-02-05 15:34:33 -0800925 final int totalLength = mTotalLength;
926 mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredHeight() +
927 lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800928 }
929
930 // Add in our padding
Romain Guy053b4802010-02-05 15:34:33 -0800931 mTotalLength += mPaddingTop + mPaddingBottom;
932 // TODO: Should we recompute the heightSpec based on the new total length?
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800933 } else {
934 alternativeMaxWidth = Math.max(alternativeMaxWidth,
935 weightedMaxWidth);
Adam Powellf8ac6b72011-05-23 18:14:09 -0700936
937
938 // We have no limit, so make all weighted views as tall as the largest child.
939 // Children will have already been measured once.
Adam Powelleabc9192012-05-04 14:49:46 -0700940 if (useLargestChild && heightMode != MeasureSpec.EXACTLY) {
Adam Powellf8ac6b72011-05-23 18:14:09 -0700941 for (int i = 0; i < count; i++) {
942 final View child = getVirtualChildAt(i);
Adam Powellf8ac6b72011-05-23 18:14:09 -0700943 if (child == null || child.getVisibility() == View.GONE) {
944 continue;
945 }
946
947 final LinearLayout.LayoutParams lp =
948 (LinearLayout.LayoutParams) child.getLayoutParams();
949
950 float childExtra = lp.weight;
951 if (childExtra > 0) {
952 child.measure(
953 MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(),
954 MeasureSpec.EXACTLY),
955 MeasureSpec.makeMeasureSpec(largestChildHeight,
956 MeasureSpec.EXACTLY));
957 }
958 }
959 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800960 }
961
962 if (!allFillParent && widthMode != MeasureSpec.EXACTLY) {
963 maxWidth = alternativeMaxWidth;
964 }
965
966 maxWidth += mPaddingLeft + mPaddingRight;
967
968 // Check against our minimum width
969 maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
970
Dianne Hackborn189ee182010-12-02 21:48:53 -0800971 setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
972 heightSizeAndState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973
974 if (matchWidth) {
975 forceUniformWidth(count, heightMeasureSpec);
976 }
977 }
978
979 private void forceUniformWidth(int count, int heightMeasureSpec) {
980 // Pretend that the linear layout has an exact size.
981 int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(),
982 MeasureSpec.EXACTLY);
983 for (int i = 0; i< count; ++i) {
984 final View child = getVirtualChildAt(i);
Alan Viverettead526932015-12-17 12:42:39 -0500985 if (child != null && child.getVisibility() != GONE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 LinearLayout.LayoutParams lp = ((LinearLayout.LayoutParams)child.getLayoutParams());
987
Romain Guy980a9382010-01-08 15:06:28 -0800988 if (lp.width == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989 // Temporarily force children to reuse their old measured height
990 // FIXME: this may not be right for something like wrapping text?
991 int oldHeight = lp.height;
992 lp.height = child.getMeasuredHeight();
993
994 // Remeasue with new dimensions
995 measureChildWithMargins(child, uniformMeasureSpec, 0, heightMeasureSpec, 0);
996 lp.height = oldHeight;
997 }
998 }
999 }
1000 }
1001
1002 /**
1003 * Measures the children when the orientation of this LinearLayout is set
1004 * to {@link #HORIZONTAL}.
1005 *
1006 * @param widthMeasureSpec Horizontal space requirements as imposed by the parent.
1007 * @param heightMeasureSpec Vertical space requirements as imposed by the parent.
1008 *
1009 * @see #getOrientation()
1010 * @see #setOrientation(int)
1011 * @see #onMeasure(int, int)
1012 */
1013 void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec) {
1014 mTotalLength = 0;
1015 int maxHeight = 0;
Dianne Hackborn189ee182010-12-02 21:48:53 -08001016 int childState = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 int alternativeMaxHeight = 0;
1018 int weightedMaxHeight = 0;
1019 boolean allFillParent = true;
1020 float totalWeight = 0;
1021
1022 final int count = getVirtualChildCount();
1023
1024 final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
1025 final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
1026
1027 boolean matchHeight = false;
Alan Viverette65be9cc2014-02-24 18:21:09 -08001028 boolean skippedMeasure = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001029
1030 if (mMaxAscent == null || mMaxDescent == null) {
1031 mMaxAscent = new int[VERTICAL_GRAVITY_COUNT];
1032 mMaxDescent = new int[VERTICAL_GRAVITY_COUNT];
1033 }
1034
1035 final int[] maxAscent = mMaxAscent;
1036 final int[] maxDescent = mMaxDescent;
1037
1038 maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
1039 maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;
1040
1041 final boolean baselineAligned = mBaselineAligned;
Romain Guy5b1b2412010-01-21 19:09:51 -08001042 final boolean useLargestChild = mUseLargestChild;
Romain Guyc3520902010-02-25 11:01:01 -08001043
1044 final boolean isExactly = widthMode == MeasureSpec.EXACTLY;
Romain Guy5b1b2412010-01-21 19:09:51 -08001045
1046 int largestChildWidth = Integer.MIN_VALUE;
Alan Viverette40e1df32015-08-25 16:50:27 -04001047 int usedExcessSpace = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048
1049 // See how wide everyone is. Also remember max height.
1050 for (int i = 0; i < count; ++i) {
1051 final View child = getVirtualChildAt(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 if (child == null) {
1053 mTotalLength += measureNullChild(i);
1054 continue;
1055 }
1056
1057 if (child.getVisibility() == GONE) {
1058 i += getChildrenSkipCount(child, i);
1059 continue;
1060 }
1061
Adam Powell696cba52011-03-29 10:38:16 -07001062 if (hasDividerBeforeChildAt(i)) {
Adam Powellfcca00a2010-11-30 21:26:29 -08001063 mTotalLength += mDividerWidth;
1064 }
1065
Alan Viverette40e1df32015-08-25 16:50:27 -04001066 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067
1068 totalWeight += lp.weight;
Alan Viverette40e1df32015-08-25 16:50:27 -04001069
1070 final boolean useExcessSpace = lp.width == 0 && lp.weight > 0;
1071 if (widthMode == MeasureSpec.EXACTLY && useExcessSpace) {
1072 // Optimization: don't bother measuring children who are only
1073 // laid out using excess space. These views will get measured
1074 // later if we have space to distribute.
Romain Guyc3520902010-02-25 11:01:01 -08001075 if (isExactly) {
1076 mTotalLength += lp.leftMargin + lp.rightMargin;
1077 } else {
1078 final int totalLength = mTotalLength;
1079 mTotalLength = Math.max(totalLength, totalLength +
1080 lp.leftMargin + lp.rightMargin);
1081 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001082
1083 // Baseline alignment requires to measure widgets to obtain the
Romain Guy6c5664a2010-02-24 18:55:22 -08001084 // baseline offset (in particular for TextViews). The following
1085 // defeats the optimization mentioned above. Allow the child to
1086 // use as much space as it wants because we can shrink things
1087 // later (and re-measure).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088 if (baselineAligned) {
Adam Powelld5dbf4b2015-06-11 13:19:24 -07001089 final int freeWidthSpec = MeasureSpec.makeSafeMeasureSpec(
Filip Gruszczynskib6824bf2015-04-13 09:16:25 -07001090 MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.UNSPECIFIED);
Adam Powelld5dbf4b2015-06-11 13:19:24 -07001091 final int freeHeightSpec = MeasureSpec.makeSafeMeasureSpec(
Filip Gruszczynskib6824bf2015-04-13 09:16:25 -07001092 MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED);
1093 child.measure(freeWidthSpec, freeHeightSpec);
Alan Viverette65be9cc2014-02-24 18:21:09 -08001094 } else {
1095 skippedMeasure = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 }
1097 } else {
Alan Viverette40e1df32015-08-25 16:50:27 -04001098 if (useExcessSpace) {
1099 // The widthMode is either UNSPECIFIED or AT_MOST, and
1100 // this child is only laid out using excess space. Measure
1101 // using WRAP_CONTENT so that we can find out the view's
1102 // optimal width. We'll restore the original width of 0
1103 // after measurement.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 lp.width = LayoutParams.WRAP_CONTENT;
1105 }
1106
1107 // Determine how big this child would like to be. If this or
1108 // previous children have given a weight, then we allow it to
1109 // use all available space (and we will shrink things later
1110 // if needed).
Alan Viverette40e1df32015-08-25 16:50:27 -04001111 final int usedWidth = totalWeight == 0 ? mTotalLength : 0;
1112 measureChildBeforeLayout(child, i, widthMeasureSpec, usedWidth,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001113 heightMeasureSpec, 0);
1114
Alan Viverette40e1df32015-08-25 16:50:27 -04001115 final int childWidth = child.getMeasuredWidth();
1116 if (useExcessSpace) {
1117 // Restore the original width and record how much space
1118 // we've allocated to excess-only children so that we can
1119 // match the behavior of EXACTLY measurement.
1120 lp.width = 0;
1121 usedExcessSpace += childWidth;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001122 }
Romain Guy5b1b2412010-01-21 19:09:51 -08001123
Romain Guyc3520902010-02-25 11:01:01 -08001124 if (isExactly) {
Alan Viverette40e1df32015-08-25 16:50:27 -04001125 mTotalLength += childWidth + lp.leftMargin + lp.rightMargin
1126 + getNextLocationOffset(child);
Romain Guyc3520902010-02-25 11:01:01 -08001127 } else {
1128 final int totalLength = mTotalLength;
Alan Viverette40e1df32015-08-25 16:50:27 -04001129 mTotalLength = Math.max(totalLength, totalLength + childWidth + lp.leftMargin
1130 + lp.rightMargin + getNextLocationOffset(child));
Romain Guyc3520902010-02-25 11:01:01 -08001131 }
Romain Guy5b1b2412010-01-21 19:09:51 -08001132
1133 if (useLargestChild) {
1134 largestChildWidth = Math.max(childWidth, largestChildWidth);
1135 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001136 }
1137
1138 boolean matchHeightLocally = false;
Romain Guy980a9382010-01-08 15:06:28 -08001139 if (heightMode != MeasureSpec.EXACTLY && lp.height == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001140 // The height of the linear layout will scale, and at least one
1141 // child said it wanted to match our height. Set a flag indicating that
1142 // we need to remeasure at least that view when we know our height.
1143 matchHeight = true;
1144 matchHeightLocally = true;
1145 }
1146
1147 final int margin = lp.topMargin + lp.bottomMargin;
1148 final int childHeight = child.getMeasuredHeight() + margin;
Dianne Hackborn189ee182010-12-02 21:48:53 -08001149 childState = combineMeasuredStates(childState, child.getMeasuredState());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150
1151 if (baselineAligned) {
1152 final int childBaseline = child.getBaseline();
1153 if (childBaseline != -1) {
1154 // Translates the child's vertical gravity into an index
1155 // in the range 0..VERTICAL_GRAVITY_COUNT
1156 final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity)
1157 & Gravity.VERTICAL_GRAVITY_MASK;
1158 final int index = ((gravity >> Gravity.AXIS_Y_SHIFT)
1159 & ~Gravity.AXIS_SPECIFIED) >> 1;
1160
1161 maxAscent[index] = Math.max(maxAscent[index], childBaseline);
1162 maxDescent[index] = Math.max(maxDescent[index], childHeight - childBaseline);
1163 }
1164 }
1165
1166 maxHeight = Math.max(maxHeight, childHeight);
1167
Romain Guy980a9382010-01-08 15:06:28 -08001168 allFillParent = allFillParent && lp.height == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169 if (lp.weight > 0) {
1170 /*
1171 * Heights of weighted Views are bogus if we end up
1172 * remeasuring, so keep them separate.
1173 */
1174 weightedMaxHeight = Math.max(weightedMaxHeight,
1175 matchHeightLocally ? margin : childHeight);
1176 } else {
1177 alternativeMaxHeight = Math.max(alternativeMaxHeight,
1178 matchHeightLocally ? margin : childHeight);
1179 }
1180
1181 i += getChildrenSkipCount(child, i);
1182 }
1183
Adam Powell696cba52011-03-29 10:38:16 -07001184 if (mTotalLength > 0 && hasDividerBeforeChildAt(count)) {
Adam Powellfcca00a2010-11-30 21:26:29 -08001185 mTotalLength += mDividerWidth;
1186 }
1187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001188 // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP,
1189 // the most common case
1190 if (maxAscent[INDEX_TOP] != -1 ||
1191 maxAscent[INDEX_CENTER_VERTICAL] != -1 ||
1192 maxAscent[INDEX_BOTTOM] != -1 ||
1193 maxAscent[INDEX_FILL] != -1) {
1194 final int ascent = Math.max(maxAscent[INDEX_FILL],
1195 Math.max(maxAscent[INDEX_CENTER_VERTICAL],
1196 Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM])));
1197 final int descent = Math.max(maxDescent[INDEX_FILL],
1198 Math.max(maxDescent[INDEX_CENTER_VERTICAL],
1199 Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM])));
1200 maxHeight = Math.max(maxHeight, ascent + descent);
1201 }
1202
Adam Powellf8ac6b72011-05-23 18:14:09 -07001203 if (useLargestChild &&
1204 (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.UNSPECIFIED)) {
Romain Guy5b1b2412010-01-21 19:09:51 -08001205 mTotalLength = 0;
1206
1207 for (int i = 0; i < count; ++i) {
1208 final View child = getVirtualChildAt(i);
Romain Guy5b1b2412010-01-21 19:09:51 -08001209 if (child == null) {
1210 mTotalLength += measureNullChild(i);
1211 continue;
1212 }
1213
1214 if (child.getVisibility() == GONE) {
1215 i += getChildrenSkipCount(child, i);
1216 continue;
1217 }
1218
1219 final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
1220 child.getLayoutParams();
Romain Guyc3520902010-02-25 11:01:01 -08001221 if (isExactly) {
1222 mTotalLength += largestChildWidth + lp.leftMargin + lp.rightMargin +
1223 getNextLocationOffset(child);
1224 } else {
1225 final int totalLength = mTotalLength;
1226 mTotalLength = Math.max(totalLength, totalLength + largestChildWidth +
1227 lp.leftMargin + lp.rightMargin + getNextLocationOffset(child));
1228 }
Romain Guy5b1b2412010-01-21 19:09:51 -08001229 }
1230 }
1231
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001232 // Add in our padding
1233 mTotalLength += mPaddingLeft + mPaddingRight;
1234
1235 int widthSize = mTotalLength;
1236
1237 // Check against our minimum width
1238 widthSize = Math.max(widthSize, getSuggestedMinimumWidth());
1239
1240 // Reconcile our calculated size with the widthMeasureSpec
Dianne Hackborn189ee182010-12-02 21:48:53 -08001241 int widthSizeAndState = resolveSizeAndState(widthSize, widthMeasureSpec, 0);
1242 widthSize = widthSizeAndState & MEASURED_SIZE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001243
1244 // Either expand children with weight to take up available space or
Alan Viverette65be9cc2014-02-24 18:21:09 -08001245 // shrink them if they extend beyond our current bounds. If we skipped
1246 // measurement on any children, we need to measure them now.
Alan Viverette40e1df32015-08-25 16:50:27 -04001247 final int delta = widthSize - mTotalLength
1248 + (mAllowInconsistentMeasurement ? 0 : usedExcessSpace);
Alan Viverette65be9cc2014-02-24 18:21:09 -08001249 if (skippedMeasure || delta != 0 && totalWeight > 0.0f) {
Alan Viverette40e1df32015-08-25 16:50:27 -04001250 final float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001251
1252 maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
1253 maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;
1254 maxHeight = -1;
1255
1256 mTotalLength = 0;
1257
1258 for (int i = 0; i < count; ++i) {
1259 final View child = getVirtualChildAt(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260 if (child == null || child.getVisibility() == View.GONE) {
1261 continue;
1262 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001263
Alan Viverette40e1df32015-08-25 16:50:27 -04001264 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
1265 final float childExtra = lp.weight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 if (childExtra > 0) {
Alan Viverette40e1df32015-08-25 16:50:27 -04001267 final int share = (int) (childExtra * delta / weightSum);
1268 final int childWidth;
1269 if (lp.width == 0 && (!mAllowInconsistentMeasurement
1270 || widthMode == MeasureSpec.EXACTLY)) {
1271 // This child needs to be laid out from scratch using
1272 // only its share of excess space.
1273 childWidth = share;
1274 } else {
1275 // This child had some intrinsic width to which we
1276 // need to add its share of excess space.
1277 childWidth = child.getMeasuredWidth() + share;
1278 }
Alan Viverette5a969df2015-07-31 12:42:10 -04001279
Alan Viverette40e1df32015-08-25 16:50:27 -04001280 final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
1281 Math.max(0, childWidth), MeasureSpec.EXACTLY);
1282 final int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin,
1284 lp.height);
Alan Viverette40e1df32015-08-25 16:50:27 -04001285 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn189ee182010-12-02 21:48:53 -08001286
1287 // Child may now not fit in horizontal dimension.
1288 childState = combineMeasuredStates(childState,
1289 child.getMeasuredState() & MEASURED_STATE_MASK);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001290 }
1291
Romain Guyc3520902010-02-25 11:01:01 -08001292 if (isExactly) {
1293 mTotalLength += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin +
1294 getNextLocationOffset(child);
1295 } else {
1296 final int totalLength = mTotalLength;
1297 mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredWidth() +
1298 lp.leftMargin + lp.rightMargin + getNextLocationOffset(child));
1299 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001300
1301 boolean matchHeightLocally = heightMode != MeasureSpec.EXACTLY &&
Romain Guy980a9382010-01-08 15:06:28 -08001302 lp.height == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001303
1304 final int margin = lp.topMargin + lp .bottomMargin;
1305 int childHeight = child.getMeasuredHeight() + margin;
1306 maxHeight = Math.max(maxHeight, childHeight);
1307 alternativeMaxHeight = Math.max(alternativeMaxHeight,
1308 matchHeightLocally ? margin : childHeight);
1309
Romain Guy980a9382010-01-08 15:06:28 -08001310 allFillParent = allFillParent && lp.height == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001311
1312 if (baselineAligned) {
1313 final int childBaseline = child.getBaseline();
1314 if (childBaseline != -1) {
1315 // Translates the child's vertical gravity into an index in the range 0..2
1316 final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity)
1317 & Gravity.VERTICAL_GRAVITY_MASK;
1318 final int index = ((gravity >> Gravity.AXIS_Y_SHIFT)
1319 & ~Gravity.AXIS_SPECIFIED) >> 1;
1320
1321 maxAscent[index] = Math.max(maxAscent[index], childBaseline);
1322 maxDescent[index] = Math.max(maxDescent[index],
1323 childHeight - childBaseline);
1324 }
1325 }
1326 }
1327
1328 // Add in our padding
1329 mTotalLength += mPaddingLeft + mPaddingRight;
Romain Guy053b4802010-02-05 15:34:33 -08001330 // TODO: Should we update widthSize with the new total length?
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001331
1332 // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP,
1333 // the most common case
1334 if (maxAscent[INDEX_TOP] != -1 ||
1335 maxAscent[INDEX_CENTER_VERTICAL] != -1 ||
1336 maxAscent[INDEX_BOTTOM] != -1 ||
1337 maxAscent[INDEX_FILL] != -1) {
1338 final int ascent = Math.max(maxAscent[INDEX_FILL],
1339 Math.max(maxAscent[INDEX_CENTER_VERTICAL],
1340 Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM])));
1341 final int descent = Math.max(maxDescent[INDEX_FILL],
1342 Math.max(maxDescent[INDEX_CENTER_VERTICAL],
1343 Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM])));
1344 maxHeight = Math.max(maxHeight, ascent + descent);
1345 }
1346 } else {
1347 alternativeMaxHeight = Math.max(alternativeMaxHeight, weightedMaxHeight);
Adam Powellf8ac6b72011-05-23 18:14:09 -07001348
1349 // We have no limit, so make all weighted views as wide as the largest child.
1350 // Children will have already been measured once.
Adam Powelleabc9192012-05-04 14:49:46 -07001351 if (useLargestChild && widthMode != MeasureSpec.EXACTLY) {
Adam Powellf8ac6b72011-05-23 18:14:09 -07001352 for (int i = 0; i < count; i++) {
1353 final View child = getVirtualChildAt(i);
Adam Powellf8ac6b72011-05-23 18:14:09 -07001354 if (child == null || child.getVisibility() == View.GONE) {
1355 continue;
1356 }
1357
1358 final LinearLayout.LayoutParams lp =
1359 (LinearLayout.LayoutParams) child.getLayoutParams();
1360
1361 float childExtra = lp.weight;
1362 if (childExtra > 0) {
1363 child.measure(
1364 MeasureSpec.makeMeasureSpec(largestChildWidth, MeasureSpec.EXACTLY),
1365 MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(),
1366 MeasureSpec.EXACTLY));
1367 }
1368 }
1369 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001370 }
1371
1372 if (!allFillParent && heightMode != MeasureSpec.EXACTLY) {
1373 maxHeight = alternativeMaxHeight;
1374 }
1375
1376 maxHeight += mPaddingTop + mPaddingBottom;
1377
1378 // Check against our minimum height
1379 maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
1380
Dianne Hackborn189ee182010-12-02 21:48:53 -08001381 setMeasuredDimension(widthSizeAndState | (childState&MEASURED_STATE_MASK),
1382 resolveSizeAndState(maxHeight, heightMeasureSpec,
1383 (childState<<MEASURED_HEIGHT_STATE_SHIFT)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384
1385 if (matchHeight) {
1386 forceUniformHeight(count, widthMeasureSpec);
1387 }
1388 }
1389
1390 private void forceUniformHeight(int count, int widthMeasureSpec) {
1391 // Pretend that the linear layout has an exact size. This is the measured height of
1392 // ourselves. The measured height should be the max height of the children, changed
Fabrice Di Megliofc53e582012-10-25 11:45:04 -07001393 // to accommodate the heightMeasureSpec from the parent
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001394 int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(),
1395 MeasureSpec.EXACTLY);
1396 for (int i = 0; i < count; ++i) {
1397 final View child = getVirtualChildAt(i);
Alan Viverettead526932015-12-17 12:42:39 -05001398 if (child != null && child.getVisibility() != GONE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001399 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
1400
Romain Guy980a9382010-01-08 15:06:28 -08001401 if (lp.height == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001402 // Temporarily force children to reuse their old measured width
1403 // FIXME: this may not be right for something like wrapping text?
1404 int oldWidth = lp.width;
1405 lp.width = child.getMeasuredWidth();
1406
1407 // Remeasure with new dimensions
1408 measureChildWithMargins(child, widthMeasureSpec, 0, uniformMeasureSpec, 0);
1409 lp.width = oldWidth;
1410 }
1411 }
1412 }
1413 }
1414
1415 /**
1416 * <p>Returns the number of children to skip after measuring/laying out
1417 * the specified child.</p>
1418 *
1419 * @param child the child after which we want to skip children
1420 * @param index the index of the child after which we want to skip children
1421 * @return the number of children to skip, 0 by default
1422 */
1423 int getChildrenSkipCount(View child, int index) {
1424 return 0;
1425 }
1426
1427 /**
1428 * <p>Returns the size (width or height) that should be occupied by a null
1429 * child.</p>
1430 *
1431 * @param childIndex the index of the null child
1432 * @return the width or height of the child depending on the orientation
1433 */
1434 int measureNullChild(int childIndex) {
1435 return 0;
1436 }
1437
1438 /**
1439 * <p>Measure the child according to the parent's measure specs. This
1440 * method should be overriden by subclasses to force the sizing of
1441 * children. This method is called by {@link #measureVertical(int, int)} and
1442 * {@link #measureHorizontal(int, int)}.</p>
1443 *
1444 * @param child the child to measure
1445 * @param childIndex the index of the child in this view
1446 * @param widthMeasureSpec horizontal space requirements as imposed by the parent
1447 * @param totalWidth extra space that has been used up by the parent horizontally
1448 * @param heightMeasureSpec vertical space requirements as imposed by the parent
1449 * @param totalHeight extra space that has been used up by the parent vertically
1450 */
1451 void measureChildBeforeLayout(View child, int childIndex,
1452 int widthMeasureSpec, int totalWidth, int heightMeasureSpec,
1453 int totalHeight) {
1454 measureChildWithMargins(child, widthMeasureSpec, totalWidth,
1455 heightMeasureSpec, totalHeight);
1456 }
1457
1458 /**
1459 * <p>Return the location offset of the specified child. This can be used
1460 * by subclasses to change the location of a given widget.</p>
1461 *
1462 * @param child the child for which to obtain the location offset
1463 * @return the location offset in pixels
1464 */
1465 int getLocationOffset(View child) {
1466 return 0;
1467 }
1468
1469 /**
1470 * <p>Return the size offset of the next sibling of the specified child.
1471 * This can be used by subclasses to change the location of the widget
1472 * following <code>child</code>.</p>
1473 *
1474 * @param child the child whose next sibling will be moved
1475 * @return the location offset of the next child in pixels
1476 */
1477 int getNextLocationOffset(View child) {
1478 return 0;
1479 }
1480
1481 @Override
1482 protected void onLayout(boolean changed, int l, int t, int r, int b) {
1483 if (mOrientation == VERTICAL) {
Philip Milnead365cc2012-09-27 14:38:46 -07001484 layoutVertical(l, t, r, b);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001485 } else {
Philip Milnead365cc2012-09-27 14:38:46 -07001486 layoutHorizontal(l, t, r, b);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001487 }
1488 }
1489
1490 /**
1491 * Position the children during a layout pass if the orientation of this
1492 * LinearLayout is set to {@link #VERTICAL}.
1493 *
1494 * @see #getOrientation()
1495 * @see #setOrientation(int)
1496 * @see #onLayout(boolean, int, int, int, int)
Philip Milnead365cc2012-09-27 14:38:46 -07001497 * @param left
1498 * @param top
1499 * @param right
1500 * @param bottom
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001501 */
Philip Milnead365cc2012-09-27 14:38:46 -07001502 void layoutVertical(int left, int top, int right, int bottom) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001503 final int paddingLeft = mPaddingLeft;
1504
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001505 int childTop;
Romain Guy5b1b2412010-01-21 19:09:51 -08001506 int childLeft;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001507
1508 // Where right end of child should go
Philip Milnead365cc2012-09-27 14:38:46 -07001509 final int width = right - left;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001510 int childRight = width - mPaddingRight;
1511
1512 // Space available for child
1513 int childSpace = width - paddingLeft - mPaddingRight;
1514
1515 final int count = getVirtualChildCount();
1516
1517 final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
Fabrice Di Meglio6a036402011-05-23 14:43:23 -07001518 final int minorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001519
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001520 switch (majorGravity) {
1521 case Gravity.BOTTOM:
1522 // mTotalLength contains the padding already
Philip Milnead365cc2012-09-27 14:38:46 -07001523 childTop = mPaddingTop + bottom - top - mTotalLength;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001524 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001525
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001526 // mTotalLength contains the padding already
1527 case Gravity.CENTER_VERTICAL:
Philip Milnead365cc2012-09-27 14:38:46 -07001528 childTop = mPaddingTop + (bottom - top - mTotalLength) / 2;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001529 break;
1530
1531 case Gravity.TOP:
1532 default:
1533 childTop = mPaddingTop;
1534 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001535 }
Adam Powellfcca00a2010-11-30 21:26:29 -08001536
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001537 for (int i = 0; i < count; i++) {
1538 final View child = getVirtualChildAt(i);
1539 if (child == null) {
1540 childTop += measureNullChild(i);
1541 } else if (child.getVisibility() != GONE) {
1542 final int childWidth = child.getMeasuredWidth();
1543 final int childHeight = child.getMeasuredHeight();
1544
1545 final LinearLayout.LayoutParams lp =
1546 (LinearLayout.LayoutParams) child.getLayoutParams();
1547
1548 int gravity = lp.gravity;
1549 if (gravity < 0) {
1550 gravity = minorGravity;
1551 }
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07001552 final int layoutDirection = getLayoutDirection();
Fabrice Di Meglioc0053222011-06-13 12:16:51 -07001553 final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
Fabrice Di Megliode35cee2011-06-01 15:13:50 -07001554 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001555 case Gravity.CENTER_HORIZONTAL:
1556 childLeft = paddingLeft + ((childSpace - childWidth) / 2)
1557 + lp.leftMargin - lp.rightMargin;
1558 break;
1559
1560 case Gravity.RIGHT:
1561 childLeft = childRight - childWidth - lp.rightMargin;
1562 break;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001563
1564 case Gravity.LEFT:
Romain Guy611cd3f2009-12-15 12:00:37 -08001565 default:
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001566 childLeft = paddingLeft + lp.leftMargin;
Romain Guy611cd3f2009-12-15 12:00:37 -08001567 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001568 }
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001569
Adam Powell696cba52011-03-29 10:38:16 -07001570 if (hasDividerBeforeChildAt(i)) {
1571 childTop += mDividerHeight;
1572 }
1573
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001574 childTop += lp.topMargin;
1575 setChildFrame(child, childLeft, childTop + getLocationOffset(child),
1576 childWidth, childHeight);
1577 childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);
1578
1579 i += getChildrenSkipCount(child, i);
1580 }
1581 }
1582 }
1583
Selim Cinek78528b22015-06-02 17:33:09 +02001584 @Override
1585 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) {
1586 super.onRtlPropertiesChanged(layoutDirection);
1587 if (layoutDirection != mLayoutDirection) {
1588 mLayoutDirection = layoutDirection;
1589 if (mOrientation == HORIZONTAL) {
1590 requestLayout();
1591 }
1592 }
1593 }
1594
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001595 /**
1596 * Position the children during a layout pass if the orientation of this
1597 * LinearLayout is set to {@link #HORIZONTAL}.
1598 *
1599 * @see #getOrientation()
1600 * @see #setOrientation(int)
1601 * @see #onLayout(boolean, int, int, int, int)
Philip Milnead365cc2012-09-27 14:38:46 -07001602 * @param left
1603 * @param top
1604 * @param right
1605 * @param bottom
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001606 */
Philip Milnead365cc2012-09-27 14:38:46 -07001607 void layoutHorizontal(int left, int top, int right, int bottom) {
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001608 final boolean isLayoutRtl = isLayoutRtl();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001609 final int paddingTop = mPaddingTop;
1610
Romain Guy5b1b2412010-01-21 19:09:51 -08001611 int childTop;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001612 int childLeft;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001613
1614 // Where bottom of child should go
Philip Milnead365cc2012-09-27 14:38:46 -07001615 final int height = bottom - top;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001616 int childBottom = height - mPaddingBottom;
1617
1618 // Space available for child
1619 int childSpace = height - paddingTop - mPaddingBottom;
1620
1621 final int count = getVirtualChildCount();
1622
Fabrice Di Meglio6a036402011-05-23 14:43:23 -07001623 final int majorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001624 final int minorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
1625
1626 final boolean baselineAligned = mBaselineAligned;
1627
1628 final int[] maxAscent = mMaxAscent;
1629 final int[] maxDescent = mMaxDescent;
1630
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07001631 final int layoutDirection = getLayoutDirection();
Fabrice Di Meglioc0053222011-06-13 12:16:51 -07001632 switch (Gravity.getAbsoluteGravity(majorGravity, layoutDirection)) {
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001633 case Gravity.RIGHT:
1634 // mTotalLength contains the padding already
Philip Milnead365cc2012-09-27 14:38:46 -07001635 childLeft = mPaddingLeft + right - left - mTotalLength;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001636 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001637
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001638 case Gravity.CENTER_HORIZONTAL:
1639 // mTotalLength contains the padding already
Philip Milnead365cc2012-09-27 14:38:46 -07001640 childLeft = mPaddingLeft + (right - left - mTotalLength) / 2;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001641 break;
1642
1643 case Gravity.LEFT:
1644 default:
1645 childLeft = mPaddingLeft;
1646 break;
1647 }
1648
1649 int start = 0;
1650 int dir = 1;
1651 //In case of RTL, start drawing from the last child.
1652 if (isLayoutRtl) {
1653 start = count - 1;
1654 dir = -1;
Adam Powellfcca00a2010-11-30 21:26:29 -08001655 }
1656
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001657 for (int i = 0; i < count; i++) {
Alan Viverettead526932015-12-17 12:42:39 -05001658 final int childIndex = start + dir * i;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001659 final View child = getVirtualChildAt(childIndex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001660 if (child == null) {
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001661 childLeft += measureNullChild(childIndex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001662 } else if (child.getVisibility() != GONE) {
1663 final int childWidth = child.getMeasuredWidth();
1664 final int childHeight = child.getMeasuredHeight();
1665 int childBaseline = -1;
1666
1667 final LinearLayout.LayoutParams lp =
1668 (LinearLayout.LayoutParams) child.getLayoutParams();
1669
Romain Guy980a9382010-01-08 15:06:28 -08001670 if (baselineAligned && lp.height != LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 childBaseline = child.getBaseline();
1672 }
1673
1674 int gravity = lp.gravity;
1675 if (gravity < 0) {
1676 gravity = minorGravity;
1677 }
1678
1679 switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
1680 case Gravity.TOP:
1681 childTop = paddingTop + lp.topMargin;
1682 if (childBaseline != -1) {
1683 childTop += maxAscent[INDEX_TOP] - childBaseline;
1684 }
1685 break;
1686
1687 case Gravity.CENTER_VERTICAL:
Romain Guy5b1b2412010-01-21 19:09:51 -08001688 // Removed support for baseline alignment when layout_gravity or
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001689 // gravity == center_vertical. See bug #1038483.
1690 // Keep the code around if we need to re-enable this feature
1691 // if (childBaseline != -1) {
1692 // // Align baselines vertically only if the child is smaller than us
1693 // if (childSpace - childHeight > 0) {
1694 // childTop = paddingTop + (childSpace / 2) - childBaseline;
1695 // } else {
1696 // childTop = paddingTop + (childSpace - childHeight) / 2;
1697 // }
1698 // } else {
1699 childTop = paddingTop + ((childSpace - childHeight) / 2)
1700 + lp.topMargin - lp.bottomMargin;
1701 break;
1702
1703 case Gravity.BOTTOM:
1704 childTop = childBottom - childHeight - lp.bottomMargin;
1705 if (childBaseline != -1) {
1706 int descent = child.getMeasuredHeight() - childBaseline;
1707 childTop -= (maxDescent[INDEX_BOTTOM] - descent);
1708 }
1709 break;
Romain Guy611cd3f2009-12-15 12:00:37 -08001710 default:
1711 childTop = paddingTop;
1712 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 }
1714
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001715 if (hasDividerBeforeChildAt(childIndex)) {
Adam Powell696cba52011-03-29 10:38:16 -07001716 childLeft += mDividerWidth;
1717 }
1718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 childLeft += lp.leftMargin;
1720 setChildFrame(child, childLeft + getLocationOffset(child), childTop,
1721 childWidth, childHeight);
1722 childLeft += childWidth + lp.rightMargin +
1723 getNextLocationOffset(child);
1724
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001725 i += getChildrenSkipCount(child, childIndex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726 }
1727 }
1728 }
1729
1730 private void setChildFrame(View child, int left, int top, int width, int height) {
1731 child.layout(left, top, left + width, top + height);
1732 }
1733
1734 /**
1735 * Should the layout be a column or a row.
Tor Norbyed9273d62013-05-30 15:59:53 -07001736 * @param orientation Pass {@link #HORIZONTAL} or {@link #VERTICAL}. Default
1737 * value is {@link #HORIZONTAL}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001738 *
1739 * @attr ref android.R.styleable#LinearLayout_orientation
1740 */
Tor Norbyed9273d62013-05-30 15:59:53 -07001741 public void setOrientation(@OrientationMode int orientation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 if (mOrientation != orientation) {
1743 mOrientation = orientation;
1744 requestLayout();
1745 }
1746 }
1747
1748 /**
1749 * Returns the current orientation.
1750 *
1751 * @return either {@link #HORIZONTAL} or {@link #VERTICAL}
1752 */
Tor Norbyed9273d62013-05-30 15:59:53 -07001753 @OrientationMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001754 public int getOrientation() {
1755 return mOrientation;
1756 }
1757
1758 /**
1759 * Describes how the child views are positioned. Defaults to GRAVITY_TOP. If
1760 * this layout has a VERTICAL orientation, this controls where all the child
1761 * views are placed if there is extra vertical space. If this layout has a
1762 * HORIZONTAL orientation, this controls the alignment of the children.
1763 *
1764 * @param gravity See {@link android.view.Gravity}
1765 *
1766 * @attr ref android.R.styleable#LinearLayout_gravity
1767 */
1768 @android.view.RemotableViewMethod
1769 public void setGravity(int gravity) {
1770 if (mGravity != gravity) {
Fabrice Di Meglio6a036402011-05-23 14:43:23 -07001771 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
Fabrice Di Meglio9e3b0022011-06-06 16:30:29 -07001772 gravity |= Gravity.START;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001773 }
1774
1775 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
1776 gravity |= Gravity.TOP;
1777 }
1778
1779 mGravity = gravity;
1780 requestLayout();
1781 }
1782 }
1783
Jason Monkefe916c2016-01-20 10:46:12 -05001784 /**
1785 * Returns the current gravity. See {@link android.view.Gravity}
1786 *
1787 * @return the current gravity.
1788 * @see #setGravity
1789 */
1790 public int getGravity() {
1791 return mGravity;
1792 }
1793
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001794 @android.view.RemotableViewMethod
1795 public void setHorizontalGravity(int horizontalGravity) {
Fabrice Di Meglio6a036402011-05-23 14:43:23 -07001796 final int gravity = horizontalGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
1797 if ((mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) != gravity) {
1798 mGravity = (mGravity & ~Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) | gravity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001799 requestLayout();
1800 }
1801 }
1802
1803 @android.view.RemotableViewMethod
1804 public void setVerticalGravity(int verticalGravity) {
1805 final int gravity = verticalGravity & Gravity.VERTICAL_GRAVITY_MASK;
1806 if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != gravity) {
1807 mGravity = (mGravity & ~Gravity.VERTICAL_GRAVITY_MASK) | gravity;
1808 requestLayout();
1809 }
1810 }
1811
1812 @Override
1813 public LayoutParams generateLayoutParams(AttributeSet attrs) {
1814 return new LinearLayout.LayoutParams(getContext(), attrs);
1815 }
1816
1817 /**
1818 * Returns a set of layout parameters with a width of
Romain Guy980a9382010-01-08 15:06:28 -08001819 * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001820 * and a height of {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}
1821 * when the layout's orientation is {@link #VERTICAL}. When the orientation is
1822 * {@link #HORIZONTAL}, the width is set to {@link LayoutParams#WRAP_CONTENT}
1823 * and the height to {@link LayoutParams#WRAP_CONTENT}.
1824 */
1825 @Override
1826 protected LayoutParams generateDefaultLayoutParams() {
1827 if (mOrientation == HORIZONTAL) {
1828 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
1829 } else if (mOrientation == VERTICAL) {
Romain Guy980a9382010-01-08 15:06:28 -08001830 return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001831 }
1832 return null;
1833 }
1834
1835 @Override
1836 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
1837 return new LayoutParams(p);
1838 }
1839
1840
1841 // Override to allow type-checking of LayoutParams.
1842 @Override
1843 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
1844 return p instanceof LinearLayout.LayoutParams;
1845 }
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08001846
1847 @Override
Dianne Hackborna7bb6fb2015-02-03 18:13:40 -08001848 public CharSequence getAccessibilityClassName() {
1849 return LinearLayout.class.getName();
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08001850 }
1851
Siva Velusamy94a6d152015-05-05 15:07:00 -07001852 /** @hide */
1853 @Override
1854 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
1855 super.encodeProperties(encoder);
1856 encoder.addProperty("layout:baselineAligned", mBaselineAligned);
1857 encoder.addProperty("layout:baselineAlignedChildIndex", mBaselineAlignedChildIndex);
1858 encoder.addProperty("measurement:baselineChildTop", mBaselineChildTop);
1859 encoder.addProperty("measurement:orientation", mOrientation);
1860 encoder.addProperty("measurement:gravity", mGravity);
1861 encoder.addProperty("measurement:totalLength", mTotalLength);
1862 encoder.addProperty("layout:totalLength", mTotalLength);
1863 encoder.addProperty("layout:useLargestChild", mUseLargestChild);
1864 }
1865
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001866 /**
1867 * Per-child layout information associated with ViewLinearLayout.
1868 *
1869 * @attr ref android.R.styleable#LinearLayout_Layout_layout_weight
1870 * @attr ref android.R.styleable#LinearLayout_Layout_layout_gravity
1871 */
1872 public static class LayoutParams extends ViewGroup.MarginLayoutParams {
1873 /**
1874 * Indicates how much of the extra space in the LinearLayout will be
1875 * allocated to the view associated with these LayoutParams. Specify
1876 * 0 if the view should not be stretched. Otherwise the extra pixels
1877 * will be pro-rated among all views whose weight is greater than 0.
1878 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07001879 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001880 public float weight;
1881
1882 /**
1883 * Gravity for the view associated with these LayoutParams.
1884 *
1885 * @see android.view.Gravity
1886 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07001887 @ViewDebug.ExportedProperty(category = "layout", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001888 @ViewDebug.IntToString(from = -1, to = "NONE"),
1889 @ViewDebug.IntToString(from = Gravity.NO_GRAVITY, to = "NONE"),
1890 @ViewDebug.IntToString(from = Gravity.TOP, to = "TOP"),
1891 @ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"),
1892 @ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"),
1893 @ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"),
Fabrice Di Meglio9e3b0022011-06-06 16:30:29 -07001894 @ViewDebug.IntToString(from = Gravity.START, to = "START"),
1895 @ViewDebug.IntToString(from = Gravity.END, to = "END"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001896 @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"),
1897 @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"),
1898 @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
1899 @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL, to = "FILL_HORIZONTAL"),
1900 @ViewDebug.IntToString(from = Gravity.CENTER, to = "CENTER"),
1901 @ViewDebug.IntToString(from = Gravity.FILL, to = "FILL")
1902 })
1903 public int gravity = -1;
1904
1905 /**
1906 * {@inheritDoc}
1907 */
1908 public LayoutParams(Context c, AttributeSet attrs) {
1909 super(c, attrs);
1910 TypedArray a =
1911 c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout_Layout);
1912
1913 weight = a.getFloat(com.android.internal.R.styleable.LinearLayout_Layout_layout_weight, 0);
1914 gravity = a.getInt(com.android.internal.R.styleable.LinearLayout_Layout_layout_gravity, -1);
1915
1916 a.recycle();
1917 }
1918
1919 /**
1920 * {@inheritDoc}
1921 */
1922 public LayoutParams(int width, int height) {
1923 super(width, height);
1924 weight = 0;
1925 }
1926
1927 /**
1928 * Creates a new set of layout parameters with the specified width, height
1929 * and weight.
1930 *
Romain Guy980a9382010-01-08 15:06:28 -08001931 * @param width the width, either {@link #MATCH_PARENT},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001932 * {@link #WRAP_CONTENT} or a fixed size in pixels
Romain Guy980a9382010-01-08 15:06:28 -08001933 * @param height the height, either {@link #MATCH_PARENT},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001934 * {@link #WRAP_CONTENT} or a fixed size in pixels
1935 * @param weight the weight
1936 */
1937 public LayoutParams(int width, int height, float weight) {
1938 super(width, height);
1939 this.weight = weight;
1940 }
1941
1942 /**
1943 * {@inheritDoc}
1944 */
1945 public LayoutParams(ViewGroup.LayoutParams p) {
1946 super(p);
1947 }
1948
1949 /**
1950 * {@inheritDoc}
1951 */
Alan Viverette0a0e1552013-08-07 13:24:09 -07001952 public LayoutParams(ViewGroup.MarginLayoutParams source) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001953 super(source);
1954 }
1955
Alan Viverette0a0e1552013-08-07 13:24:09 -07001956 /**
1957 * Copy constructor. Clones the width, height, margin values, weight,
1958 * and gravity of the source.
1959 *
1960 * @param source The layout params to copy from.
1961 */
1962 public LayoutParams(LayoutParams source) {
1963 super(source);
1964
1965 this.weight = source.weight;
1966 this.gravity = source.gravity;
1967 }
1968
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001969 @Override
1970 public String debug(String output) {
1971 return output + "LinearLayout.LayoutParams={width=" + sizeToString(width) +
1972 ", height=" + sizeToString(height) + " weight=" + weight + "}";
1973 }
Siva Velusamy94a6d152015-05-05 15:07:00 -07001974
1975 /** @hide */
1976 @Override
1977 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
1978 super.encodeProperties(encoder);
1979
1980 encoder.addProperty("layout:weight", weight);
1981 encoder.addProperty("layout:gravity", gravity);
1982 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001983 }
1984}