blob: 452e9036cc54bce09f9b24f8321d7a4ed8e4d60f [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
Tor Norbyed9273d62013-05-30 15:59:53 -070019import android.annotation.IntDef;
Siva Velusamy94a6d152015-05-05 15:07:00 -070020import android.annotation.NonNull;
Scott Kennedy3a1fa102015-03-05 19:15:11 -080021import android.annotation.Nullable;
Mathew Inwooda85f4eb2018-08-21 16:08:34 +010022import android.annotation.UnsupportedAppUsage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.content.Context;
24import android.content.res.TypedArray;
Adam Powellfcca00a2010-11-30 21:26:29 -080025import android.graphics.Canvas;
26import android.graphics.drawable.Drawable;
Alan Viverette40e1df32015-08-25 16:50:27 -040027import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.util.AttributeSet;
29import android.view.Gravity;
30import android.view.View;
31import android.view.ViewDebug;
32import android.view.ViewGroup;
Siva Velusamy94a6d152015-05-05 15:07:00 -070033import android.view.ViewHierarchyEncoder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.widget.RemoteViews.RemoteView;
35
Aurimas Liutikas99441c52016-10-11 16:48:32 -070036import com.android.internal.R;
37
Tor Norbyed9273d62013-05-30 15:59:53 -070038import java.lang.annotation.Retention;
39import java.lang.annotation.RetentionPolicy;
40
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041
42/**
Joe Fernandezd9ffaa52017-04-25 23:39:17 -070043 * A layout that arranges other views either horizontally in a single column
44 * or vertically in a single row.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045 *
Joe Fernandezd9ffaa52017-04-25 23:39:17 -070046 * <p>The following snippet shows how to include a linear layout in your layout XML file:</p>
Scott Main41ec6532010-08-19 16:57:07 -070047 *
Joe Fernandezd9ffaa52017-04-25 23:39:17 -070048 * <pre>&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
49 * android:layout_width="match_parent"
50 * android:layout_height="match_parent"
51 * android:paddingLeft="16dp"
52 * android:paddingRight="16dp"
53 * android:orientation="horizontal"
54 * android:gravity="center"&gt;
55 *
56 * &lt;!-- Include other widget or layout tags here. These are considered
57 * "child views" or "children" of the linear layout --&gt;
58 *
59 * &lt;/LinearLayout&gt;</pre>
60 *
61 * <p>Set {@link android.R.styleable#LinearLayout_orientation android:orientation} to specify
62 * whether child views are displayed in a row or column.</p>
63 *
64 * <p>To control how linear layout aligns all the views it contains, set a value for
65 * {@link android.R.styleable#LinearLayout_gravity android:gravity}. For example, the
66 * snippet above sets android:gravity to "center". The value you set affects
67 * both horizontal and vertical alignment of all child views within the single row or column.</p>
68 *
69 * <p>You can set
Jeff Sharkey67f9d502017-08-05 13:49:13 -060070 * {@link android.R.styleable#LinearLayout_Layout_layout_weight android:layout_weight}
Joe Fernandezd9ffaa52017-04-25 23:39:17 -070071 * on individual child views to specify how linear layout divides remaining space amongst
72 * the views it contains. See the
73 * <a href="https://developer.android.com/guide/topics/ui/layout/linear.html">Linear Layout</a>
74 * guide for an example.</p>
75 *
76 * <p>See
77 * {@link android.widget.LinearLayout.LayoutParams LinearLayout.LayoutParams}
78 * to learn about other attributes you can set on a child view to affect its
79 * position and size in the containing linear layout.</p>
Romain Guy9295ada2010-06-15 11:33:24 -070080 *
81 * @attr ref android.R.styleable#LinearLayout_baselineAligned
82 * @attr ref android.R.styleable#LinearLayout_baselineAlignedChildIndex
83 * @attr ref android.R.styleable#LinearLayout_gravity
84 * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
85 * @attr ref android.R.styleable#LinearLayout_orientation
86 * @attr ref android.R.styleable#LinearLayout_weightSum
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 */
88@RemoteView
89public class LinearLayout extends ViewGroup {
Tor Norbyed9273d62013-05-30 15:59:53 -070090 /** @hide */
91 @IntDef({HORIZONTAL, VERTICAL})
92 @Retention(RetentionPolicy.SOURCE)
93 public @interface OrientationMode {}
94
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095 public static final int HORIZONTAL = 0;
96 public static final int VERTICAL = 1;
97
Tor Norbyed9273d62013-05-30 15:59:53 -070098 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -070099 @IntDef(flag = true, prefix = { "SHOW_DIVIDER_" }, value = {
100 SHOW_DIVIDER_NONE,
101 SHOW_DIVIDER_BEGINNING,
102 SHOW_DIVIDER_MIDDLE,
103 SHOW_DIVIDER_END
104 })
Tor Norbyed9273d62013-05-30 15:59:53 -0700105 @Retention(RetentionPolicy.SOURCE)
106 public @interface DividerMode {}
107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 /**
Adam Powellfcca00a2010-11-30 21:26:29 -0800109 * Don't show any dividers.
110 */
111 public static final int SHOW_DIVIDER_NONE = 0;
112 /**
113 * Show a divider at the beginning of the group.
114 */
115 public static final int SHOW_DIVIDER_BEGINNING = 1;
116 /**
117 * Show dividers between each item in the group.
118 */
119 public static final int SHOW_DIVIDER_MIDDLE = 2;
120 /**
121 * Show a divider at the end of the group.
122 */
123 public static final int SHOW_DIVIDER_END = 4;
124
125 /**
Alan Viverette40e1df32015-08-25 16:50:27 -0400126 * Compatibility check. Old versions of the platform would give different
127 * results from measurement passes using EXACTLY and non-EXACTLY modes,
128 * even when the resulting size was the same.
129 */
130 private final boolean mAllowInconsistentMeasurement;
131
132 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 * Whether the children of this layout are baseline aligned. Only applicable
134 * if {@link #mOrientation} is horizontal.
135 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700136 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 private boolean mBaselineAligned = true;
138
139 /**
140 * If this layout is part of another layout that is baseline aligned,
141 * use the child at this index as the baseline.
142 *
143 * Note: this is orthogonal to {@link #mBaselineAligned}, which is concerned
144 * with whether the children of this layout are baseline aligned.
145 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700146 @ViewDebug.ExportedProperty(category = "layout")
Karl Rosaenc1f9c402009-08-12 17:18:33 -0700147 private int mBaselineAlignedChildIndex = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148
149 /**
150 * The additional offset to the child's baseline.
151 * We'll calculate the baseline of this layout as we measure vertically; for
152 * horizontal linear layouts, the offset of 0 is appropriate.
153 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700154 @ViewDebug.ExportedProperty(category = "measurement")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 private int mBaselineChildTop = 0;
156
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700157 @ViewDebug.ExportedProperty(category = "measurement")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 private int mOrientation;
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700159
Fabrice Di Megliobce84d22011-06-02 15:57:01 -0700160 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = {
161 @ViewDebug.FlagToString(mask = -1,
162 equals = -1, name = "NONE"),
163 @ViewDebug.FlagToString(mask = Gravity.NO_GRAVITY,
164 equals = Gravity.NO_GRAVITY,name = "NONE"),
165 @ViewDebug.FlagToString(mask = Gravity.TOP,
166 equals = Gravity.TOP, name = "TOP"),
167 @ViewDebug.FlagToString(mask = Gravity.BOTTOM,
168 equals = Gravity.BOTTOM, name = "BOTTOM"),
169 @ViewDebug.FlagToString(mask = Gravity.LEFT,
170 equals = Gravity.LEFT, name = "LEFT"),
171 @ViewDebug.FlagToString(mask = Gravity.RIGHT,
172 equals = Gravity.RIGHT, name = "RIGHT"),
Fabrice Di Meglio9e3b0022011-06-06 16:30:29 -0700173 @ViewDebug.FlagToString(mask = Gravity.START,
174 equals = Gravity.START, name = "START"),
175 @ViewDebug.FlagToString(mask = Gravity.END,
176 equals = Gravity.END, name = "END"),
Fabrice Di Megliobce84d22011-06-02 15:57:01 -0700177 @ViewDebug.FlagToString(mask = Gravity.CENTER_VERTICAL,
178 equals = Gravity.CENTER_VERTICAL, name = "CENTER_VERTICAL"),
179 @ViewDebug.FlagToString(mask = Gravity.FILL_VERTICAL,
180 equals = Gravity.FILL_VERTICAL, name = "FILL_VERTICAL"),
181 @ViewDebug.FlagToString(mask = Gravity.CENTER_HORIZONTAL,
182 equals = Gravity.CENTER_HORIZONTAL, name = "CENTER_HORIZONTAL"),
183 @ViewDebug.FlagToString(mask = Gravity.FILL_HORIZONTAL,
184 equals = Gravity.FILL_HORIZONTAL, name = "FILL_HORIZONTAL"),
185 @ViewDebug.FlagToString(mask = Gravity.CENTER,
186 equals = Gravity.CENTER, name = "CENTER"),
187 @ViewDebug.FlagToString(mask = Gravity.FILL,
188 equals = Gravity.FILL, name = "FILL"),
Fabrice Di Meglioc46f7ff2011-06-06 18:23:10 -0700189 @ViewDebug.FlagToString(mask = Gravity.RELATIVE_LAYOUT_DIRECTION,
190 equals = Gravity.RELATIVE_LAYOUT_DIRECTION, name = "RELATIVE")
Jon Miranda4597e982014-07-29 07:25:49 -0700191 }, formatToHexString = true)
Mathew Inwooda85f4eb2018-08-21 16:08:34 +0100192 @UnsupportedAppUsage
Fabrice Di Meglio9e3b0022011-06-06 16:30:29 -0700193 private int mGravity = Gravity.START | Gravity.TOP;
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700194
195 @ViewDebug.ExportedProperty(category = "measurement")
Mathew Inwooda85f4eb2018-08-21 16:08:34 +0100196 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 private int mTotalLength;
198
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700199 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 private float mWeightSum;
201
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700202 @ViewDebug.ExportedProperty(category = "layout")
Mathew Inwooda85f4eb2018-08-21 16:08:34 +0100203 @UnsupportedAppUsage
Romain Guy5b1b2412010-01-21 19:09:51 -0800204 private boolean mUseLargestChild;
205
Mathew Inwooda85f4eb2018-08-21 16:08:34 +0100206 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 private int[] mMaxAscent;
Mathew Inwooda85f4eb2018-08-21 16:08:34 +0100208 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 private int[] mMaxDescent;
210
211 private static final int VERTICAL_GRAVITY_COUNT = 4;
212
213 private static final int INDEX_CENTER_VERTICAL = 0;
Mathew Inwooda85f4eb2018-08-21 16:08:34 +0100214 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 private static final int INDEX_TOP = 1;
Mathew Inwooda85f4eb2018-08-21 16:08:34 +0100216 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 private static final int INDEX_BOTTOM = 2;
Romain Guy5b1b2412010-01-21 19:09:51 -0800218 private static final int INDEX_FILL = 3;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219
Mathew Inwooda85f4eb2018-08-21 16:08:34 +0100220 @UnsupportedAppUsage
Adam Powellfcca00a2010-11-30 21:26:29 -0800221 private Drawable mDivider;
222 private int mDividerWidth;
223 private int mDividerHeight;
224 private int mShowDividers;
225 private int mDividerPadding;
226
Selim Cinek78528b22015-06-02 17:33:09 +0200227 private int mLayoutDirection = View.LAYOUT_DIRECTION_UNDEFINED;
228
Chet Haasecb848882018-03-21 14:09:44 -0700229 /**
230 * Signals that compatibility booleans have been initialized according to
231 * target SDK versions.
232 */
233 private static boolean sCompatibilityDone = false;
234
235 /**
236 * Behavior change in P; always remeasure weighted children, regardless of excess space.
237 */
238 private static boolean sRemeasureWeightedChildren = true;
239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 public LinearLayout(Context context) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700241 this(context, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 }
243
Scott Kennedy3a1fa102015-03-05 19:15:11 -0800244 public LinearLayout(Context context, @Nullable AttributeSet attrs) {
Romain Guy9295ada2010-06-15 11:33:24 -0700245 this(context, attrs, 0);
246 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700247
Scott Kennedy3a1fa102015-03-05 19:15:11 -0800248 public LinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
Alan Viverette617feb92013-09-09 18:09:13 -0700249 this(context, attrs, defStyleAttr, 0);
250 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251
Alan Viverette617feb92013-09-09 18:09:13 -0700252 public LinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
253 super(context, attrs, defStyleAttr, defStyleRes);
254
Chet Haasecb848882018-03-21 14:09:44 -0700255 if (!sCompatibilityDone && context != null) {
256 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
257
258 // Older apps only remeasure non-zero children
259 sRemeasureWeightedChildren = targetSdkVersion >= Build.VERSION_CODES.P;
260
261 sCompatibilityDone = true;
262 }
263
Alan Viverette617feb92013-09-09 18:09:13 -0700264 final TypedArray a = context.obtainStyledAttributes(
265 attrs, com.android.internal.R.styleable.LinearLayout, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266
267 int index = a.getInt(com.android.internal.R.styleable.LinearLayout_orientation, -1);
268 if (index >= 0) {
269 setOrientation(index);
270 }
271
272 index = a.getInt(com.android.internal.R.styleable.LinearLayout_gravity, -1);
273 if (index >= 0) {
274 setGravity(index);
275 }
276
277 boolean baselineAligned = a.getBoolean(R.styleable.LinearLayout_baselineAligned, true);
278 if (!baselineAligned) {
279 setBaselineAligned(baselineAligned);
280 }
281
282 mWeightSum = a.getFloat(R.styleable.LinearLayout_weightSum, -1.0f);
283
284 mBaselineAlignedChildIndex =
285 a.getInt(com.android.internal.R.styleable.LinearLayout_baselineAlignedChildIndex, -1);
286
Romain Guy9295ada2010-06-15 11:33:24 -0700287 mUseLargestChild = a.getBoolean(R.styleable.LinearLayout_measureWithLargestChild, false);
Romain Guy5b1b2412010-01-21 19:09:51 -0800288
Adam Powellfcca00a2010-11-30 21:26:29 -0800289 mShowDividers = a.getInt(R.styleable.LinearLayout_showDividers, SHOW_DIVIDER_NONE);
290 mDividerPadding = a.getDimensionPixelSize(R.styleable.LinearLayout_dividerPadding, 0);
Kirill Grouchnikov3218a4e2017-04-26 17:45:28 -0400291 setDividerDrawable(a.getDrawable(R.styleable.LinearLayout_divider));
Adam Powellfcca00a2010-11-30 21:26:29 -0800292
Alan Viverette40e1df32015-08-25 16:50:27 -0400293 final int version = context.getApplicationInfo().targetSdkVersion;
294 mAllowInconsistentMeasurement = version <= Build.VERSION_CODES.M;
295
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 a.recycle();
297 }
298
299 /**
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400300 * Returns <code>true</code> if this layout is currently configured to show at least one
301 * divider.
302 */
303 private boolean isShowingDividers() {
304 return (mShowDividers != SHOW_DIVIDER_NONE) && (mDivider != null);
305 }
306
307 /**
Adam Powellfcca00a2010-11-30 21:26:29 -0800308 * Set how dividers should be shown between items in this layout
309 *
310 * @param showDividers One or more of {@link #SHOW_DIVIDER_BEGINNING},
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400311 * {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END}
312 * to show dividers, or {@link #SHOW_DIVIDER_NONE} to show no dividers.
Adam Powellfcca00a2010-11-30 21:26:29 -0800313 */
Tor Norbyed9273d62013-05-30 15:59:53 -0700314 public void setShowDividers(@DividerMode int showDividers) {
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400315 if (showDividers == mShowDividers) {
316 return;
Adam Powellfcca00a2010-11-30 21:26:29 -0800317 }
318 mShowDividers = showDividers;
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400319
320 setWillNotDraw(!isShowingDividers());
321 requestLayout();
Adam Powellfcca00a2010-11-30 21:26:29 -0800322 }
323
Patrick Dubroye0a799a2011-05-04 16:19:22 -0700324 @Override
325 public boolean shouldDelayChildPressedState() {
326 return false;
327 }
328
Adam Powellfcca00a2010-11-30 21:26:29 -0800329 /**
330 * @return A flag set indicating how dividers should be shown around items.
331 * @see #setShowDividers(int)
332 */
Tor Norbyed9273d62013-05-30 15:59:53 -0700333 @DividerMode
Adam Powellfcca00a2010-11-30 21:26:29 -0800334 public int getShowDividers() {
335 return mShowDividers;
336 }
337
338 /**
Philip Milne1018fb42012-03-13 12:00:04 -0700339 * @return the divider Drawable that will divide each item.
340 *
341 * @see #setDividerDrawable(Drawable)
342 *
343 * @attr ref android.R.styleable#LinearLayout_divider
344 */
345 public Drawable getDividerDrawable() {
346 return mDivider;
347 }
348
349 /**
Adam Powellfcca00a2010-11-30 21:26:29 -0800350 * Set a drawable to be used as a divider between items.
Philip Milne1018fb42012-03-13 12:00:04 -0700351 *
Adam Powellfcca00a2010-11-30 21:26:29 -0800352 * @param divider Drawable that will divide each item.
Philip Milne1018fb42012-03-13 12:00:04 -0700353 *
Adam Powellfcca00a2010-11-30 21:26:29 -0800354 * @see #setShowDividers(int)
Philip Milne1018fb42012-03-13 12:00:04 -0700355 *
356 * @attr ref android.R.styleable#LinearLayout_divider
Adam Powellfcca00a2010-11-30 21:26:29 -0800357 */
358 public void setDividerDrawable(Drawable divider) {
359 if (divider == mDivider) {
360 return;
361 }
362 mDivider = divider;
363 if (divider != null) {
364 mDividerWidth = divider.getIntrinsicWidth();
365 mDividerHeight = divider.getIntrinsicHeight();
366 } else {
367 mDividerWidth = 0;
368 mDividerHeight = 0;
369 }
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400370
371 setWillNotDraw(!isShowingDividers());
Adam Powellfcca00a2010-11-30 21:26:29 -0800372 requestLayout();
373 }
374
Adam Powell696cba52011-03-29 10:38:16 -0700375 /**
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400376 * Set padding displayed on both ends of dividers. For a vertical layout, the padding is applied
377 * to left and right end of dividers. For a horizontal layout, the padding is applied to top and
378 * bottom end of dividers.
Adam Powell696cba52011-03-29 10:38:16 -0700379 *
380 * @param padding Padding value in pixels that will be applied to each end
381 *
382 * @see #setShowDividers(int)
383 * @see #setDividerDrawable(Drawable)
384 * @see #getDividerPadding()
385 */
386 public void setDividerPadding(int padding) {
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400387 if (padding == mDividerPadding) {
388 return;
389 }
Adam Powell696cba52011-03-29 10:38:16 -0700390 mDividerPadding = padding;
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400391
392 if (isShowingDividers()) {
393 requestLayout();
394 invalidate();
395 }
Adam Powell696cba52011-03-29 10:38:16 -0700396 }
397
398 /**
399 * Get the padding size used to inset dividers in pixels
400 *
401 * @see #setShowDividers(int)
402 * @see #setDividerDrawable(Drawable)
403 * @see #setDividerPadding(int)
404 */
405 public int getDividerPadding() {
406 return mDividerPadding;
407 }
408
Adam Powell640a66e2011-04-29 10:18:53 -0700409 /**
410 * Get the width of the current divider drawable.
411 *
412 * @hide Used internally by framework.
413 */
414 public int getDividerWidth() {
415 return mDividerWidth;
416 }
417
Adam Powellfcca00a2010-11-30 21:26:29 -0800418 @Override
419 protected void onDraw(Canvas canvas) {
420 if (mDivider == null) {
421 return;
422 }
423
424 if (mOrientation == VERTICAL) {
425 drawDividersVertical(canvas);
426 } else {
427 drawDividersHorizontal(canvas);
428 }
429 }
430
431 void drawDividersVertical(Canvas canvas) {
Adam Powellfcca00a2010-11-30 21:26:29 -0800432 final int count = getVirtualChildCount();
Adam Powellfcca00a2010-11-30 21:26:29 -0800433 for (int i = 0; i < count; i++) {
434 final View child = getVirtualChildAt(i);
Adam Powell35aecd52011-07-01 13:43:49 -0700435 if (child != null && child.getVisibility() != GONE) {
Adam Powell696cba52011-03-29 10:38:16 -0700436 if (hasDividerBeforeChildAt(i)) {
Adam Powell35aecd52011-07-01 13:43:49 -0700437 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Vladimir Baryshnikov20761fc2012-01-17 14:59:48 -0800438 final int top = child.getTop() - lp.topMargin - mDividerHeight;
Adam Powellfcca00a2010-11-30 21:26:29 -0800439 drawHorizontalDivider(canvas, top);
Adam Powellfcca00a2010-11-30 21:26:29 -0800440 }
Adam Powellfcca00a2010-11-30 21:26:29 -0800441 }
442 }
443
Adam Powell696cba52011-03-29 10:38:16 -0700444 if (hasDividerBeforeChildAt(count)) {
Doris Liuec6a4cd2015-06-25 15:16:54 -0700445 final View child = getLastNonGoneChild();
Adam Powell35aecd52011-07-01 13:43:49 -0700446 int bottom = 0;
447 if (child == null) {
448 bottom = getHeight() - getPaddingBottom() - mDividerHeight;
449 } else {
450 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
451 bottom = child.getBottom() + lp.bottomMargin;
452 }
453 drawHorizontalDivider(canvas, bottom);
Adam Powellfcca00a2010-11-30 21:26:29 -0800454 }
455 }
456
Doris Liuec6a4cd2015-06-25 15:16:54 -0700457 /**
458 * Finds the last child that is not gone. The last child will be used as the reference for
459 * where the end divider should be drawn.
460 */
461 private View getLastNonGoneChild() {
462 for (int i = getVirtualChildCount() - 1; i >= 0; i--) {
Alan Viverettead526932015-12-17 12:42:39 -0500463 final View child = getVirtualChildAt(i);
Doris Liuec6a4cd2015-06-25 15:16:54 -0700464 if (child != null && child.getVisibility() != GONE) {
465 return child;
466 }
467 }
468 return null;
469 }
470
Adam Powellfcca00a2010-11-30 21:26:29 -0800471 void drawDividersHorizontal(Canvas canvas) {
Adam Powellfcca00a2010-11-30 21:26:29 -0800472 final int count = getVirtualChildCount();
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700473 final boolean isLayoutRtl = isLayoutRtl();
Adam Powellfcca00a2010-11-30 21:26:29 -0800474 for (int i = 0; i < count; i++) {
475 final View child = getVirtualChildAt(i);
Adam Powell35aecd52011-07-01 13:43:49 -0700476 if (child != null && child.getVisibility() != GONE) {
Adam Powell696cba52011-03-29 10:38:16 -0700477 if (hasDividerBeforeChildAt(i)) {
Adam Powell35aecd52011-07-01 13:43:49 -0700478 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700479 final int position;
480 if (isLayoutRtl) {
481 position = child.getRight() + lp.rightMargin;
482 } else {
483 position = child.getLeft() - lp.leftMargin - mDividerWidth;
484 }
485 drawVerticalDivider(canvas, position);
Adam Powellfcca00a2010-11-30 21:26:29 -0800486 }
Adam Powellfcca00a2010-11-30 21:26:29 -0800487 }
488 }
489
Adam Powell696cba52011-03-29 10:38:16 -0700490 if (hasDividerBeforeChildAt(count)) {
Doris Liuec6a4cd2015-06-25 15:16:54 -0700491 final View child = getLastNonGoneChild();
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700492 int position;
Adam Powell35aecd52011-07-01 13:43:49 -0700493 if (child == null) {
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700494 if (isLayoutRtl) {
495 position = getPaddingLeft();
496 } else {
497 position = getWidth() - getPaddingRight() - mDividerWidth;
498 }
Adam Powell35aecd52011-07-01 13:43:49 -0700499 } else {
500 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700501 if (isLayoutRtl) {
502 position = child.getLeft() - lp.leftMargin - mDividerWidth;
503 } else {
504 position = child.getRight() + lp.rightMargin;
505 }
Adam Powell35aecd52011-07-01 13:43:49 -0700506 }
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700507 drawVerticalDivider(canvas, position);
Adam Powellfcca00a2010-11-30 21:26:29 -0800508 }
509 }
510
511 void drawHorizontalDivider(Canvas canvas, int top) {
512 mDivider.setBounds(getPaddingLeft() + mDividerPadding, top,
513 getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);
514 mDivider.draw(canvas);
515 }
516
517 void drawVerticalDivider(Canvas canvas, int left) {
518 mDivider.setBounds(left, getPaddingTop() + mDividerPadding,
519 left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding);
520 mDivider.draw(canvas);
521 }
522
523 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 * <p>Indicates whether widgets contained within this layout are aligned
525 * on their baseline or not.</p>
526 *
527 * @return true when widgets are baseline-aligned, false otherwise
528 */
529 public boolean isBaselineAligned() {
530 return mBaselineAligned;
531 }
532
533 /**
534 * <p>Defines whether widgets contained in this layout are
535 * baseline-aligned or not.</p>
536 *
537 * @param baselineAligned true to align widgets on their baseline,
538 * false otherwise
539 *
540 * @attr ref android.R.styleable#LinearLayout_baselineAligned
541 */
542 @android.view.RemotableViewMethod
543 public void setBaselineAligned(boolean baselineAligned) {
544 mBaselineAligned = baselineAligned;
545 }
546
Romain Guy9295ada2010-06-15 11:33:24 -0700547 /**
548 * When true, all children with a weight will be considered having
549 * the minimum size of the largest child. If false, all children are
550 * measured normally.
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700551 *
Romain Guy9295ada2010-06-15 11:33:24 -0700552 * @return True to measure children with a weight using the minimum
553 * size of the largest child, false otherwise.
Philip Milne1018fb42012-03-13 12:00:04 -0700554 *
555 * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
Romain Guy9295ada2010-06-15 11:33:24 -0700556 */
557 public boolean isMeasureWithLargestChildEnabled() {
558 return mUseLargestChild;
559 }
560
561 /**
562 * When set to true, all children with a weight will be considered having
563 * the minimum size of the largest child. If false, all children are
564 * measured normally.
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700565 *
Romain Guy9295ada2010-06-15 11:33:24 -0700566 * Disabled by default.
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700567 *
Romain Guy9295ada2010-06-15 11:33:24 -0700568 * @param enabled True to measure children with a weight using the
569 * minimum size of the largest child, false otherwise.
Philip Milne1018fb42012-03-13 12:00:04 -0700570 *
571 * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
Romain Guy9295ada2010-06-15 11:33:24 -0700572 */
573 @android.view.RemotableViewMethod
574 public void setMeasureWithLargestChildEnabled(boolean enabled) {
575 mUseLargestChild = enabled;
576 }
577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 @Override
579 public int getBaseline() {
580 if (mBaselineAlignedChildIndex < 0) {
581 return super.getBaseline();
582 }
583
584 if (getChildCount() <= mBaselineAlignedChildIndex) {
585 throw new RuntimeException("mBaselineAlignedChildIndex of LinearLayout "
586 + "set to an index that is out of bounds.");
587 }
588
589 final View child = getChildAt(mBaselineAlignedChildIndex);
590 final int childBaseline = child.getBaseline();
591
592 if (childBaseline == -1) {
593 if (mBaselineAlignedChildIndex == 0) {
594 // this is just the default case, safe to return -1
595 return -1;
596 }
597 // the user picked an index that points to something that doesn't
598 // know how to calculate its baseline.
599 throw new RuntimeException("mBaselineAlignedChildIndex of LinearLayout "
600 + "points to a View that doesn't know how to get its baseline.");
601 }
602
603 // TODO: This should try to take into account the virtual offsets
604 // (See getNextLocationOffset and getLocationOffset)
605 // We should add to childTop:
606 // sum([getNextLocationOffset(getChildAt(i)) / i < mBaselineAlignedChildIndex])
607 // and also add:
608 // getLocationOffset(child)
609 int childTop = mBaselineChildTop;
610
611 if (mOrientation == VERTICAL) {
612 final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
613 if (majorGravity != Gravity.TOP) {
614 switch (majorGravity) {
615 case Gravity.BOTTOM:
616 childTop = mBottom - mTop - mPaddingBottom - mTotalLength;
617 break;
618
619 case Gravity.CENTER_VERTICAL:
620 childTop += ((mBottom - mTop - mPaddingTop - mPaddingBottom) -
621 mTotalLength) / 2;
622 break;
623 }
624 }
625 }
626
627 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
628 return childTop + lp.topMargin + childBaseline;
629 }
630
631 /**
632 * @return The index of the child that will be used if this layout is
633 * part of a larger layout that is baseline aligned, or -1 if none has
634 * been set.
635 */
636 public int getBaselineAlignedChildIndex() {
637 return mBaselineAlignedChildIndex;
638 }
639
640 /**
641 * @param i The index of the child that will be used if this layout is
642 * part of a larger layout that is baseline aligned.
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700643 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800644 * @attr ref android.R.styleable#LinearLayout_baselineAlignedChildIndex
645 */
646 @android.view.RemotableViewMethod
647 public void setBaselineAlignedChildIndex(int i) {
648 if ((i < 0) || (i >= getChildCount())) {
649 throw new IllegalArgumentException("base aligned child index out "
650 + "of range (0, " + getChildCount() + ")");
651 }
652 mBaselineAlignedChildIndex = i;
653 }
654
655 /**
656 * <p>Returns the view at the specified index. This method can be overriden
657 * to take into account virtual children. Refer to
658 * {@link android.widget.TableLayout} and {@link android.widget.TableRow}
659 * for an example.</p>
660 *
661 * @param index the child's index
Alan Viverettead526932015-12-17 12:42:39 -0500662 * @return the child at the specified index, may be {@code null}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800663 */
Alan Viverettead526932015-12-17 12:42:39 -0500664 @Nullable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 View getVirtualChildAt(int index) {
666 return getChildAt(index);
667 }
668
669 /**
670 * <p>Returns the virtual number of children. This number might be different
671 * than the actual number of children if the layout can hold virtual
672 * children. Refer to
673 * {@link android.widget.TableLayout} and {@link android.widget.TableRow}
674 * for an example.</p>
675 *
676 * @return the virtual number of children
677 */
678 int getVirtualChildCount() {
679 return getChildCount();
680 }
681
682 /**
683 * Returns the desired weights sum.
684 *
685 * @return A number greater than 0.0f if the weight sum is defined, or
686 * a number lower than or equals to 0.0f if not weight sum is
687 * to be used.
688 */
689 public float getWeightSum() {
690 return mWeightSum;
691 }
692
693 /**
694 * Defines the desired weights sum. If unspecified the weights sum is computed
695 * at layout time by adding the layout_weight of each child.
696 *
697 * This can be used for instance to give a single child 50% of the total
698 * available space by giving it a layout_weight of 0.5 and setting the
699 * weightSum to 1.0.
700 *
701 * @param weightSum a number greater than 0.0f, or a number lower than or equals
702 * to 0.0f if the weight sum should be computed from the children's
703 * layout_weight
704 */
705 @android.view.RemotableViewMethod
706 public void setWeightSum(float weightSum) {
707 mWeightSum = Math.max(0.0f, weightSum);
708 }
709
710 @Override
711 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
712 if (mOrientation == VERTICAL) {
713 measureVertical(widthMeasureSpec, heightMeasureSpec);
714 } else {
715 measureHorizontal(widthMeasureSpec, heightMeasureSpec);
716 }
717 }
718
719 /**
Adam Powell696cba52011-03-29 10:38:16 -0700720 * Determines where to position dividers between children.
721 *
722 * @param childIndex Index of child to check for preceding divider
723 * @return true if there should be a divider before the child at childIndex
724 * @hide Pending API consideration. Currently only used internally by the system.
725 */
726 protected boolean hasDividerBeforeChildAt(int childIndex) {
Doris Liuec6a4cd2015-06-25 15:16:54 -0700727 if (childIndex == getVirtualChildCount()) {
728 // Check whether the end divider should draw.
Adam Powell696cba52011-03-29 10:38:16 -0700729 return (mShowDividers & SHOW_DIVIDER_END) != 0;
Adam Powell696cba52011-03-29 10:38:16 -0700730 }
Doris Liuec6a4cd2015-06-25 15:16:54 -0700731 boolean allViewsAreGoneBefore = allViewsAreGoneBefore(childIndex);
732 if (allViewsAreGoneBefore) {
733 // This is the first view that's not gone, check if beginning divider is enabled.
734 return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0;
735 } else {
736 return (mShowDividers & SHOW_DIVIDER_MIDDLE) != 0;
737 }
738 }
739
740 /**
741 * Checks whether all (virtual) child views before the given index are gone.
742 */
743 private boolean allViewsAreGoneBefore(int childIndex) {
744 for (int i = childIndex - 1; i >= 0; i--) {
Alan Viverettead526932015-12-17 12:42:39 -0500745 final View child = getVirtualChildAt(i);
Doris Liuf102d422015-06-30 13:42:22 -0700746 if (child != null && child.getVisibility() != GONE) {
Doris Liuec6a4cd2015-06-25 15:16:54 -0700747 return false;
748 }
749 }
750 return true;
Adam Powell696cba52011-03-29 10:38:16 -0700751 }
752
753 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800754 * Measures the children when the orientation of this LinearLayout is set
755 * to {@link #VERTICAL}.
756 *
757 * @param widthMeasureSpec Horizontal space requirements as imposed by the parent.
758 * @param heightMeasureSpec Vertical space requirements as imposed by the parent.
759 *
760 * @see #getOrientation()
761 * @see #setOrientation(int)
762 * @see #onMeasure(int, int)
763 */
764 void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
765 mTotalLength = 0;
766 int maxWidth = 0;
Dianne Hackborn189ee182010-12-02 21:48:53 -0800767 int childState = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 int alternativeMaxWidth = 0;
769 int weightedMaxWidth = 0;
770 boolean allFillParent = true;
771 float totalWeight = 0;
772
773 final int count = getVirtualChildCount();
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700774
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800775 final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
776 final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
777
778 boolean matchWidth = false;
Alan Viverette65be9cc2014-02-24 18:21:09 -0800779 boolean skippedMeasure = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700781 final int baselineChildIndex = mBaselineAlignedChildIndex;
Romain Guy5b1b2412010-01-21 19:09:51 -0800782 final boolean useLargestChild = mUseLargestChild;
783
784 int largestChildHeight = Integer.MIN_VALUE;
Alan Viverette40e1df32015-08-25 16:50:27 -0400785 int consumedExcessSpace = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400787 int nonSkippedChildCount = 0;
788
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800789 // See how tall everyone is. Also remember max width.
790 for (int i = 0; i < count; ++i) {
791 final View child = getVirtualChildAt(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 if (child == null) {
793 mTotalLength += measureNullChild(i);
794 continue;
795 }
796
797 if (child.getVisibility() == View.GONE) {
798 i += getChildrenSkipCount(child, i);
799 continue;
800 }
801
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400802 nonSkippedChildCount++;
Adam Powell696cba52011-03-29 10:38:16 -0700803 if (hasDividerBeforeChildAt(i)) {
Adam Powellfcca00a2010-11-30 21:26:29 -0800804 mTotalLength += mDividerHeight;
805 }
806
Alan Viverette40e1df32015-08-25 16:50:27 -0400807 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Alan Viverette61c41bf2016-05-05 17:52:10 +0000808
809 totalWeight += lp.weight;
Alan Viverette40e1df32015-08-25 16:50:27 -0400810
811 final boolean useExcessSpace = lp.height == 0 && lp.weight > 0;
812 if (heightMode == MeasureSpec.EXACTLY && useExcessSpace) {
813 // Optimization: don't bother measuring children who are only
814 // laid out using excess space. These views will get measured
815 // later if we have space to distribute.
Romain Guy053b4802010-02-05 15:34:33 -0800816 final int totalLength = mTotalLength;
817 mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);
Alan Viverette65be9cc2014-02-24 18:21:09 -0800818 skippedMeasure = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 } else {
Alan Viverette40e1df32015-08-25 16:50:27 -0400820 if (useExcessSpace) {
821 // The heightMode is either UNSPECIFIED or AT_MOST, and
822 // this child is only laid out using excess space. Measure
823 // using WRAP_CONTENT so that we can find out the view's
824 // optimal height. We'll restore the original height of 0
825 // after measurement.
Gilles Debunnef5c6eff2010-02-09 19:08:36 -0800826 lp.height = LayoutParams.WRAP_CONTENT;
Romain Guy5b1b2412010-01-21 19:09:51 -0800827 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828
Gilles Debunnef5c6eff2010-02-09 19:08:36 -0800829 // Determine how big this child would like to be. If this or
Romain Guy5b1b2412010-01-21 19:09:51 -0800830 // previous children have given a weight, then we allow it to
831 // use all available space (and we will shrink things later
832 // if needed).
Alan Viverette40e1df32015-08-25 16:50:27 -0400833 final int usedHeight = totalWeight == 0 ? mTotalLength : 0;
834 measureChildBeforeLayout(child, i, widthMeasureSpec, 0,
835 heightMeasureSpec, usedHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836
Alan Viverette5a969df2015-07-31 12:42:10 -0400837 final int childHeight = child.getMeasuredHeight();
Alan Viverette40e1df32015-08-25 16:50:27 -0400838 if (useExcessSpace) {
839 // Restore the original height and record how much space
840 // we've allocated to excess-only children so that we can
841 // match the behavior of EXACTLY measurement.
842 lp.height = 0;
843 consumedExcessSpace += childHeight;
844 }
845
Romain Guy053b4802010-02-05 15:34:33 -0800846 final int totalLength = mTotalLength;
847 mTotalLength = Math.max(totalLength, totalLength + childHeight + lp.topMargin +
848 lp.bottomMargin + getNextLocationOffset(child));
Romain Guy5b1b2412010-01-21 19:09:51 -0800849
850 if (useLargestChild) {
851 largestChildHeight = Math.max(childHeight, largestChildHeight);
852 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 }
854
855 /**
856 * If applicable, compute the additional offset to the child's baseline
857 * we'll need later when asked {@link #getBaseline}.
858 */
859 if ((baselineChildIndex >= 0) && (baselineChildIndex == i + 1)) {
860 mBaselineChildTop = mTotalLength;
861 }
862
863 // if we are trying to use a child index for our baseline, the above
864 // book keeping only works if there are no children above it with
865 // weight. fail fast to aid the developer.
866 if (i < baselineChildIndex && lp.weight > 0) {
867 throw new RuntimeException("A child of LinearLayout with index "
868 + "less than mBaselineAlignedChildIndex has weight > 0, which "
869 + "won't work. Either remove the weight, or don't set "
870 + "mBaselineAlignedChildIndex.");
871 }
872
873 boolean matchWidthLocally = false;
Romain Guy980a9382010-01-08 15:06:28 -0800874 if (widthMode != MeasureSpec.EXACTLY && lp.width == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 // The width of the linear layout will scale, and at least one
876 // child said it wanted to match our width. Set a flag
877 // indicating that we need to remeasure at least that view when
878 // we know our width.
879 matchWidth = true;
880 matchWidthLocally = true;
881 }
882
883 final int margin = lp.leftMargin + lp.rightMargin;
884 final int measuredWidth = child.getMeasuredWidth() + margin;
885 maxWidth = Math.max(maxWidth, measuredWidth);
Dianne Hackborn189ee182010-12-02 21:48:53 -0800886 childState = combineMeasuredStates(childState, child.getMeasuredState());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800887
Romain Guy980a9382010-01-08 15:06:28 -0800888 allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889 if (lp.weight > 0) {
890 /*
891 * Widths of weighted Views are bogus if we end up
892 * remeasuring, so keep them separate.
893 */
894 weightedMaxWidth = Math.max(weightedMaxWidth,
895 matchWidthLocally ? margin : measuredWidth);
896 } else {
897 alternativeMaxWidth = Math.max(alternativeMaxWidth,
898 matchWidthLocally ? margin : measuredWidth);
899 }
900
901 i += getChildrenSkipCount(child, i);
902 }
Romain Guy5b1b2412010-01-21 19:09:51 -0800903
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400904 if (nonSkippedChildCount > 0 && hasDividerBeforeChildAt(count)) {
Adam Powellfcca00a2010-11-30 21:26:29 -0800905 mTotalLength += mDividerHeight;
906 }
907
Adam Powellf8ac6b72011-05-23 18:14:09 -0700908 if (useLargestChild &&
909 (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED)) {
Romain Guy5b1b2412010-01-21 19:09:51 -0800910 mTotalLength = 0;
911
912 for (int i = 0; i < count; ++i) {
913 final View child = getVirtualChildAt(i);
Romain Guy5b1b2412010-01-21 19:09:51 -0800914 if (child == null) {
915 mTotalLength += measureNullChild(i);
916 continue;
917 }
918
919 if (child.getVisibility() == GONE) {
920 i += getChildrenSkipCount(child, i);
921 continue;
922 }
923
924 final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
925 child.getLayoutParams();
Romain Guy053b4802010-02-05 15:34:33 -0800926 // Account for negative margins
927 final int totalLength = mTotalLength;
928 mTotalLength = Math.max(totalLength, totalLength + largestChildHeight +
929 lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));
Romain Guy5b1b2412010-01-21 19:09:51 -0800930 }
931 }
932
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800933 // Add in our padding
934 mTotalLength += mPaddingTop + mPaddingBottom;
935
936 int heightSize = mTotalLength;
937
938 // Check against our minimum height
939 heightSize = Math.max(heightSize, getSuggestedMinimumHeight());
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700940
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 // Reconcile our calculated size with the heightMeasureSpec
Dianne Hackborn189ee182010-12-02 21:48:53 -0800942 int heightSizeAndState = resolveSizeAndState(heightSize, heightMeasureSpec, 0);
943 heightSize = heightSizeAndState & MEASURED_SIZE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800944 // Either expand children with weight to take up available space or
Alan Viverette65be9cc2014-02-24 18:21:09 -0800945 // shrink them if they extend beyond our current bounds. If we skipped
946 // measurement on any children, we need to measure them now.
Alan Viverette918f8862016-03-17 12:28:31 -0400947 int remainingExcess = heightSize - mTotalLength
Alan Viverette40e1df32015-08-25 16:50:27 -0400948 + (mAllowInconsistentMeasurement ? 0 : consumedExcessSpace);
Chet Haasecb848882018-03-21 14:09:44 -0700949 if (skippedMeasure
950 || ((sRemeasureWeightedChildren || remainingExcess != 0) && totalWeight > 0.0f)) {
Alan Viverette918f8862016-03-17 12:28:31 -0400951 float remainingWeightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952
953 mTotalLength = 0;
954
955 for (int i = 0; i < count; ++i) {
956 final View child = getVirtualChildAt(i);
Alan Viverette40e1df32015-08-25 16:50:27 -0400957 if (child == null || child.getVisibility() == View.GONE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 continue;
959 }
Alan Viverette40e1df32015-08-25 16:50:27 -0400960
961 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Alan Viverette918f8862016-03-17 12:28:31 -0400962 final float childWeight = lp.weight;
963 if (childWeight > 0) {
Alan Viverette61c41bf2016-05-05 17:52:10 +0000964 final int share = (int) (childWeight * remainingExcess / remainingWeightSum);
Alan Viverette918f8862016-03-17 12:28:31 -0400965 remainingExcess -= share;
966 remainingWeightSum -= childWeight;
967
Alan Viverette40e1df32015-08-25 16:50:27 -0400968 final int childHeight;
Alan Viverette070b22b2016-06-30 11:15:36 -0400969 if (mUseLargestChild && heightMode != MeasureSpec.EXACTLY) {
970 childHeight = largestChildHeight;
971 } else if (lp.height == 0 && (!mAllowInconsistentMeasurement
Alan Viverette40e1df32015-08-25 16:50:27 -0400972 || heightMode == MeasureSpec.EXACTLY)) {
973 // This child needs to be laid out from scratch using
974 // only its share of excess space.
975 childHeight = share;
Alan Viverette5a969df2015-07-31 12:42:10 -0400976 } else {
Alan Viverette40e1df32015-08-25 16:50:27 -0400977 // This child had some intrinsic height to which we
978 // need to add its share of excess space.
979 childHeight = child.getMeasuredHeight() + share;
Alan Viverette5a969df2015-07-31 12:42:10 -0400980 }
Dianne Hackborn189ee182010-12-02 21:48:53 -0800981
Alan Viverette40e1df32015-08-25 16:50:27 -0400982 final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
983 Math.max(0, childHeight), MeasureSpec.EXACTLY);
984 final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
985 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin,
986 lp.width);
987 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
988
Dianne Hackborn189ee182010-12-02 21:48:53 -0800989 // Child may now not fit in vertical dimension.
990 childState = combineMeasuredStates(childState, child.getMeasuredState()
991 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992 }
993
994 final int margin = lp.leftMargin + lp.rightMargin;
995 final int measuredWidth = child.getMeasuredWidth() + margin;
996 maxWidth = Math.max(maxWidth, measuredWidth);
997
998 boolean matchWidthLocally = widthMode != MeasureSpec.EXACTLY &&
Romain Guy980a9382010-01-08 15:06:28 -0800999 lp.width == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000
1001 alternativeMaxWidth = Math.max(alternativeMaxWidth,
1002 matchWidthLocally ? margin : measuredWidth);
1003
Romain Guy980a9382010-01-08 15:06:28 -08001004 allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005
Romain Guy053b4802010-02-05 15:34:33 -08001006 final int totalLength = mTotalLength;
1007 mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredHeight() +
1008 lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009 }
1010
1011 // Add in our padding
Romain Guy053b4802010-02-05 15:34:33 -08001012 mTotalLength += mPaddingTop + mPaddingBottom;
1013 // TODO: Should we recompute the heightSpec based on the new total length?
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001014 } else {
1015 alternativeMaxWidth = Math.max(alternativeMaxWidth,
1016 weightedMaxWidth);
Adam Powellf8ac6b72011-05-23 18:14:09 -07001017
1018
1019 // We have no limit, so make all weighted views as tall as the largest child.
1020 // Children will have already been measured once.
Adam Powelleabc9192012-05-04 14:49:46 -07001021 if (useLargestChild && heightMode != MeasureSpec.EXACTLY) {
Adam Powellf8ac6b72011-05-23 18:14:09 -07001022 for (int i = 0; i < count; i++) {
1023 final View child = getVirtualChildAt(i);
Adam Powellf8ac6b72011-05-23 18:14:09 -07001024 if (child == null || child.getVisibility() == View.GONE) {
1025 continue;
1026 }
1027
1028 final LinearLayout.LayoutParams lp =
1029 (LinearLayout.LayoutParams) child.getLayoutParams();
1030
1031 float childExtra = lp.weight;
1032 if (childExtra > 0) {
1033 child.measure(
1034 MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(),
1035 MeasureSpec.EXACTLY),
1036 MeasureSpec.makeMeasureSpec(largestChildHeight,
1037 MeasureSpec.EXACTLY));
1038 }
1039 }
1040 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041 }
1042
1043 if (!allFillParent && widthMode != MeasureSpec.EXACTLY) {
1044 maxWidth = alternativeMaxWidth;
1045 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001046
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 maxWidth += mPaddingLeft + mPaddingRight;
1048
1049 // Check against our minimum width
1050 maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001051
Dianne Hackborn189ee182010-12-02 21:48:53 -08001052 setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
1053 heightSizeAndState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001054
1055 if (matchWidth) {
1056 forceUniformWidth(count, heightMeasureSpec);
1057 }
1058 }
1059
1060 private void forceUniformWidth(int count, int heightMeasureSpec) {
1061 // Pretend that the linear layout has an exact size.
1062 int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(),
1063 MeasureSpec.EXACTLY);
1064 for (int i = 0; i< count; ++i) {
1065 final View child = getVirtualChildAt(i);
Alan Viverettead526932015-12-17 12:42:39 -05001066 if (child != null && child.getVisibility() != GONE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 LinearLayout.LayoutParams lp = ((LinearLayout.LayoutParams)child.getLayoutParams());
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001068
Romain Guy980a9382010-01-08 15:06:28 -08001069 if (lp.width == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001070 // Temporarily force children to reuse their old measured height
1071 // FIXME: this may not be right for something like wrapping text?
1072 int oldHeight = lp.height;
1073 lp.height = child.getMeasuredHeight();
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001074
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001075 // Remeasue with new dimensions
1076 measureChildWithMargins(child, uniformMeasureSpec, 0, heightMeasureSpec, 0);
1077 lp.height = oldHeight;
1078 }
1079 }
1080 }
1081 }
1082
1083 /**
1084 * Measures the children when the orientation of this LinearLayout is set
1085 * to {@link #HORIZONTAL}.
1086 *
1087 * @param widthMeasureSpec Horizontal space requirements as imposed by the parent.
1088 * @param heightMeasureSpec Vertical space requirements as imposed by the parent.
1089 *
1090 * @see #getOrientation()
1091 * @see #setOrientation(int)
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001092 * @see #onMeasure(int, int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001093 */
1094 void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec) {
1095 mTotalLength = 0;
1096 int maxHeight = 0;
Dianne Hackborn189ee182010-12-02 21:48:53 -08001097 int childState = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001098 int alternativeMaxHeight = 0;
1099 int weightedMaxHeight = 0;
1100 boolean allFillParent = true;
1101 float totalWeight = 0;
1102
1103 final int count = getVirtualChildCount();
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001104
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001105 final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
1106 final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
1107
1108 boolean matchHeight = false;
Alan Viverette65be9cc2014-02-24 18:21:09 -08001109 boolean skippedMeasure = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110
1111 if (mMaxAscent == null || mMaxDescent == null) {
1112 mMaxAscent = new int[VERTICAL_GRAVITY_COUNT];
1113 mMaxDescent = new int[VERTICAL_GRAVITY_COUNT];
1114 }
1115
1116 final int[] maxAscent = mMaxAscent;
1117 final int[] maxDescent = mMaxDescent;
1118
1119 maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
1120 maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;
1121
1122 final boolean baselineAligned = mBaselineAligned;
Romain Guy5b1b2412010-01-21 19:09:51 -08001123 final boolean useLargestChild = mUseLargestChild;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001124
Romain Guyc3520902010-02-25 11:01:01 -08001125 final boolean isExactly = widthMode == MeasureSpec.EXACTLY;
Romain Guy5b1b2412010-01-21 19:09:51 -08001126
1127 int largestChildWidth = Integer.MIN_VALUE;
Alan Viverette40e1df32015-08-25 16:50:27 -04001128 int usedExcessSpace = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001129
Kirill Grouchnikov9df08462016-04-26 15:28:25 -04001130 int nonSkippedChildCount = 0;
1131
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132 // See how wide everyone is. Also remember max height.
1133 for (int i = 0; i < count; ++i) {
1134 final View child = getVirtualChildAt(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001135 if (child == null) {
1136 mTotalLength += measureNullChild(i);
1137 continue;
1138 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001139
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001140 if (child.getVisibility() == GONE) {
1141 i += getChildrenSkipCount(child, i);
1142 continue;
1143 }
1144
Kirill Grouchnikov9df08462016-04-26 15:28:25 -04001145 nonSkippedChildCount++;
Adam Powell696cba52011-03-29 10:38:16 -07001146 if (hasDividerBeforeChildAt(i)) {
Adam Powellfcca00a2010-11-30 21:26:29 -08001147 mTotalLength += mDividerWidth;
1148 }
1149
Alan Viverette40e1df32015-08-25 16:50:27 -04001150 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Alan Viverette61c41bf2016-05-05 17:52:10 +00001151
1152 totalWeight += lp.weight;
Alan Viverette40e1df32015-08-25 16:50:27 -04001153
1154 final boolean useExcessSpace = lp.width == 0 && lp.weight > 0;
1155 if (widthMode == MeasureSpec.EXACTLY && useExcessSpace) {
1156 // Optimization: don't bother measuring children who are only
1157 // laid out using excess space. These views will get measured
1158 // later if we have space to distribute.
Romain Guyc3520902010-02-25 11:01:01 -08001159 if (isExactly) {
1160 mTotalLength += lp.leftMargin + lp.rightMargin;
1161 } else {
1162 final int totalLength = mTotalLength;
1163 mTotalLength = Math.max(totalLength, totalLength +
1164 lp.leftMargin + lp.rightMargin);
1165 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001166
1167 // Baseline alignment requires to measure widgets to obtain the
Romain Guy6c5664a2010-02-24 18:55:22 -08001168 // baseline offset (in particular for TextViews). The following
1169 // defeats the optimization mentioned above. Allow the child to
1170 // use as much space as it wants because we can shrink things
1171 // later (and re-measure).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001172 if (baselineAligned) {
Adam Powelld5dbf4b2015-06-11 13:19:24 -07001173 final int freeWidthSpec = MeasureSpec.makeSafeMeasureSpec(
Filip Gruszczynskib6824bf2015-04-13 09:16:25 -07001174 MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.UNSPECIFIED);
Adam Powelld5dbf4b2015-06-11 13:19:24 -07001175 final int freeHeightSpec = MeasureSpec.makeSafeMeasureSpec(
Filip Gruszczynskib6824bf2015-04-13 09:16:25 -07001176 MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED);
1177 child.measure(freeWidthSpec, freeHeightSpec);
Alan Viverette65be9cc2014-02-24 18:21:09 -08001178 } else {
1179 skippedMeasure = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 }
1181 } else {
Alan Viverette40e1df32015-08-25 16:50:27 -04001182 if (useExcessSpace) {
1183 // The widthMode is either UNSPECIFIED or AT_MOST, and
1184 // this child is only laid out using excess space. Measure
1185 // using WRAP_CONTENT so that we can find out the view's
1186 // optimal width. We'll restore the original width of 0
1187 // after measurement.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001188 lp.width = LayoutParams.WRAP_CONTENT;
1189 }
1190
1191 // Determine how big this child would like to be. If this or
1192 // previous children have given a weight, then we allow it to
1193 // use all available space (and we will shrink things later
1194 // if needed).
Alan Viverette40e1df32015-08-25 16:50:27 -04001195 final int usedWidth = totalWeight == 0 ? mTotalLength : 0;
1196 measureChildBeforeLayout(child, i, widthMeasureSpec, usedWidth,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001197 heightMeasureSpec, 0);
1198
Alan Viverette40e1df32015-08-25 16:50:27 -04001199 final int childWidth = child.getMeasuredWidth();
1200 if (useExcessSpace) {
1201 // Restore the original width and record how much space
1202 // we've allocated to excess-only children so that we can
1203 // match the behavior of EXACTLY measurement.
1204 lp.width = 0;
1205 usedExcessSpace += childWidth;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001206 }
Romain Guy5b1b2412010-01-21 19:09:51 -08001207
Romain Guyc3520902010-02-25 11:01:01 -08001208 if (isExactly) {
Alan Viverette40e1df32015-08-25 16:50:27 -04001209 mTotalLength += childWidth + lp.leftMargin + lp.rightMargin
1210 + getNextLocationOffset(child);
Romain Guyc3520902010-02-25 11:01:01 -08001211 } else {
1212 final int totalLength = mTotalLength;
Alan Viverette40e1df32015-08-25 16:50:27 -04001213 mTotalLength = Math.max(totalLength, totalLength + childWidth + lp.leftMargin
1214 + lp.rightMargin + getNextLocationOffset(child));
Romain Guyc3520902010-02-25 11:01:01 -08001215 }
Romain Guy5b1b2412010-01-21 19:09:51 -08001216
1217 if (useLargestChild) {
1218 largestChildWidth = Math.max(childWidth, largestChildWidth);
1219 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001220 }
1221
1222 boolean matchHeightLocally = false;
Romain Guy980a9382010-01-08 15:06:28 -08001223 if (heightMode != MeasureSpec.EXACTLY && lp.height == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001224 // The height of the linear layout will scale, and at least one
1225 // child said it wanted to match our height. Set a flag indicating that
1226 // we need to remeasure at least that view when we know our height.
1227 matchHeight = true;
1228 matchHeightLocally = true;
1229 }
1230
1231 final int margin = lp.topMargin + lp.bottomMargin;
1232 final int childHeight = child.getMeasuredHeight() + margin;
Dianne Hackborn189ee182010-12-02 21:48:53 -08001233 childState = combineMeasuredStates(childState, child.getMeasuredState());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001234
1235 if (baselineAligned) {
1236 final int childBaseline = child.getBaseline();
1237 if (childBaseline != -1) {
1238 // Translates the child's vertical gravity into an index
1239 // in the range 0..VERTICAL_GRAVITY_COUNT
1240 final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity)
1241 & Gravity.VERTICAL_GRAVITY_MASK;
1242 final int index = ((gravity >> Gravity.AXIS_Y_SHIFT)
1243 & ~Gravity.AXIS_SPECIFIED) >> 1;
1244
1245 maxAscent[index] = Math.max(maxAscent[index], childBaseline);
1246 maxDescent[index] = Math.max(maxDescent[index], childHeight - childBaseline);
1247 }
1248 }
1249
1250 maxHeight = Math.max(maxHeight, childHeight);
1251
Romain Guy980a9382010-01-08 15:06:28 -08001252 allFillParent = allFillParent && lp.height == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001253 if (lp.weight > 0) {
1254 /*
1255 * Heights of weighted Views are bogus if we end up
1256 * remeasuring, so keep them separate.
1257 */
1258 weightedMaxHeight = Math.max(weightedMaxHeight,
1259 matchHeightLocally ? margin : childHeight);
1260 } else {
1261 alternativeMaxHeight = Math.max(alternativeMaxHeight,
1262 matchHeightLocally ? margin : childHeight);
1263 }
1264
1265 i += getChildrenSkipCount(child, i);
1266 }
1267
Kirill Grouchnikov9df08462016-04-26 15:28:25 -04001268 if (nonSkippedChildCount > 0 && hasDividerBeforeChildAt(count)) {
Adam Powellfcca00a2010-11-30 21:26:29 -08001269 mTotalLength += mDividerWidth;
1270 }
1271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001272 // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP,
1273 // the most common case
1274 if (maxAscent[INDEX_TOP] != -1 ||
1275 maxAscent[INDEX_CENTER_VERTICAL] != -1 ||
1276 maxAscent[INDEX_BOTTOM] != -1 ||
1277 maxAscent[INDEX_FILL] != -1) {
1278 final int ascent = Math.max(maxAscent[INDEX_FILL],
1279 Math.max(maxAscent[INDEX_CENTER_VERTICAL],
1280 Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM])));
1281 final int descent = Math.max(maxDescent[INDEX_FILL],
1282 Math.max(maxDescent[INDEX_CENTER_VERTICAL],
1283 Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM])));
1284 maxHeight = Math.max(maxHeight, ascent + descent);
1285 }
1286
Adam Powellf8ac6b72011-05-23 18:14:09 -07001287 if (useLargestChild &&
1288 (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.UNSPECIFIED)) {
Romain Guy5b1b2412010-01-21 19:09:51 -08001289 mTotalLength = 0;
1290
1291 for (int i = 0; i < count; ++i) {
1292 final View child = getVirtualChildAt(i);
Romain Guy5b1b2412010-01-21 19:09:51 -08001293 if (child == null) {
1294 mTotalLength += measureNullChild(i);
1295 continue;
1296 }
1297
1298 if (child.getVisibility() == GONE) {
1299 i += getChildrenSkipCount(child, i);
1300 continue;
1301 }
1302
1303 final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
1304 child.getLayoutParams();
Romain Guyc3520902010-02-25 11:01:01 -08001305 if (isExactly) {
1306 mTotalLength += largestChildWidth + lp.leftMargin + lp.rightMargin +
1307 getNextLocationOffset(child);
1308 } else {
1309 final int totalLength = mTotalLength;
1310 mTotalLength = Math.max(totalLength, totalLength + largestChildWidth +
1311 lp.leftMargin + lp.rightMargin + getNextLocationOffset(child));
1312 }
Romain Guy5b1b2412010-01-21 19:09:51 -08001313 }
1314 }
1315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316 // Add in our padding
1317 mTotalLength += mPaddingLeft + mPaddingRight;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001318
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001319 int widthSize = mTotalLength;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001320
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001321 // Check against our minimum width
1322 widthSize = Math.max(widthSize, getSuggestedMinimumWidth());
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001324 // Reconcile our calculated size with the widthMeasureSpec
Dianne Hackborn189ee182010-12-02 21:48:53 -08001325 int widthSizeAndState = resolveSizeAndState(widthSize, widthMeasureSpec, 0);
1326 widthSize = widthSizeAndState & MEASURED_SIZE_MASK;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001327
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001328 // Either expand children with weight to take up available space or
Alan Viverette65be9cc2014-02-24 18:21:09 -08001329 // shrink them if they extend beyond our current bounds. If we skipped
1330 // measurement on any children, we need to measure them now.
Alan Viverette918f8862016-03-17 12:28:31 -04001331 int remainingExcess = widthSize - mTotalLength
Alan Viverette40e1df32015-08-25 16:50:27 -04001332 + (mAllowInconsistentMeasurement ? 0 : usedExcessSpace);
Chet Haasecb848882018-03-21 14:09:44 -07001333 if (skippedMeasure
1334 || ((sRemeasureWeightedChildren || remainingExcess != 0) && totalWeight > 0.0f)) {
Alan Viverette918f8862016-03-17 12:28:31 -04001335 float remainingWeightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001336
1337 maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
1338 maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;
1339 maxHeight = -1;
1340
1341 mTotalLength = 0;
1342
1343 for (int i = 0; i < count; ++i) {
1344 final View child = getVirtualChildAt(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001345 if (child == null || child.getVisibility() == View.GONE) {
1346 continue;
1347 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001348
Alan Viverette40e1df32015-08-25 16:50:27 -04001349 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Alan Viverette918f8862016-03-17 12:28:31 -04001350 final float childWeight = lp.weight;
1351 if (childWeight > 0) {
Alan Viverette61c41bf2016-05-05 17:52:10 +00001352 final int share = (int) (childWeight * remainingExcess / remainingWeightSum);
Alan Viverette918f8862016-03-17 12:28:31 -04001353 remainingExcess -= share;
1354 remainingWeightSum -= childWeight;
1355
Alan Viverette40e1df32015-08-25 16:50:27 -04001356 final int childWidth;
Alan Viverette070b22b2016-06-30 11:15:36 -04001357 if (mUseLargestChild && widthMode != MeasureSpec.EXACTLY) {
1358 childWidth = largestChildWidth;
1359 } else if (lp.width == 0 && (!mAllowInconsistentMeasurement
Alan Viverette40e1df32015-08-25 16:50:27 -04001360 || widthMode == MeasureSpec.EXACTLY)) {
1361 // This child needs to be laid out from scratch using
1362 // only its share of excess space.
1363 childWidth = share;
1364 } else {
1365 // This child had some intrinsic width to which we
1366 // need to add its share of excess space.
1367 childWidth = child.getMeasuredWidth() + share;
1368 }
Alan Viverette5a969df2015-07-31 12:42:10 -04001369
Alan Viverette40e1df32015-08-25 16:50:27 -04001370 final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
1371 Math.max(0, childWidth), MeasureSpec.EXACTLY);
1372 final int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001373 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin,
1374 lp.height);
Alan Viverette40e1df32015-08-25 16:50:27 -04001375 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn189ee182010-12-02 21:48:53 -08001376
1377 // Child may now not fit in horizontal dimension.
1378 childState = combineMeasuredStates(childState,
1379 child.getMeasuredState() & MEASURED_STATE_MASK);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001380 }
1381
Romain Guyc3520902010-02-25 11:01:01 -08001382 if (isExactly) {
1383 mTotalLength += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin +
1384 getNextLocationOffset(child);
1385 } else {
1386 final int totalLength = mTotalLength;
1387 mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredWidth() +
1388 lp.leftMargin + lp.rightMargin + getNextLocationOffset(child));
1389 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001390
1391 boolean matchHeightLocally = heightMode != MeasureSpec.EXACTLY &&
Romain Guy980a9382010-01-08 15:06:28 -08001392 lp.height == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001393
1394 final int margin = lp.topMargin + lp .bottomMargin;
1395 int childHeight = child.getMeasuredHeight() + margin;
1396 maxHeight = Math.max(maxHeight, childHeight);
1397 alternativeMaxHeight = Math.max(alternativeMaxHeight,
1398 matchHeightLocally ? margin : childHeight);
1399
Romain Guy980a9382010-01-08 15:06:28 -08001400 allFillParent = allFillParent && lp.height == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401
1402 if (baselineAligned) {
1403 final int childBaseline = child.getBaseline();
1404 if (childBaseline != -1) {
1405 // Translates the child's vertical gravity into an index in the range 0..2
1406 final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity)
1407 & Gravity.VERTICAL_GRAVITY_MASK;
1408 final int index = ((gravity >> Gravity.AXIS_Y_SHIFT)
1409 & ~Gravity.AXIS_SPECIFIED) >> 1;
1410
1411 maxAscent[index] = Math.max(maxAscent[index], childBaseline);
1412 maxDescent[index] = Math.max(maxDescent[index],
1413 childHeight - childBaseline);
1414 }
1415 }
1416 }
1417
1418 // Add in our padding
1419 mTotalLength += mPaddingLeft + mPaddingRight;
Romain Guy053b4802010-02-05 15:34:33 -08001420 // TODO: Should we update widthSize with the new total length?
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001421
1422 // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP,
1423 // the most common case
1424 if (maxAscent[INDEX_TOP] != -1 ||
1425 maxAscent[INDEX_CENTER_VERTICAL] != -1 ||
1426 maxAscent[INDEX_BOTTOM] != -1 ||
1427 maxAscent[INDEX_FILL] != -1) {
1428 final int ascent = Math.max(maxAscent[INDEX_FILL],
1429 Math.max(maxAscent[INDEX_CENTER_VERTICAL],
1430 Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM])));
1431 final int descent = Math.max(maxDescent[INDEX_FILL],
1432 Math.max(maxDescent[INDEX_CENTER_VERTICAL],
1433 Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM])));
1434 maxHeight = Math.max(maxHeight, ascent + descent);
1435 }
1436 } else {
1437 alternativeMaxHeight = Math.max(alternativeMaxHeight, weightedMaxHeight);
Adam Powellf8ac6b72011-05-23 18:14:09 -07001438
1439 // We have no limit, so make all weighted views as wide as the largest child.
1440 // Children will have already been measured once.
Adam Powelleabc9192012-05-04 14:49:46 -07001441 if (useLargestChild && widthMode != MeasureSpec.EXACTLY) {
Adam Powellf8ac6b72011-05-23 18:14:09 -07001442 for (int i = 0; i < count; i++) {
1443 final View child = getVirtualChildAt(i);
Adam Powellf8ac6b72011-05-23 18:14:09 -07001444 if (child == null || child.getVisibility() == View.GONE) {
1445 continue;
1446 }
1447
1448 final LinearLayout.LayoutParams lp =
1449 (LinearLayout.LayoutParams) child.getLayoutParams();
1450
1451 float childExtra = lp.weight;
1452 if (childExtra > 0) {
1453 child.measure(
1454 MeasureSpec.makeMeasureSpec(largestChildWidth, MeasureSpec.EXACTLY),
1455 MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(),
1456 MeasureSpec.EXACTLY));
1457 }
1458 }
1459 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 }
1461
1462 if (!allFillParent && heightMode != MeasureSpec.EXACTLY) {
1463 maxHeight = alternativeMaxHeight;
1464 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001465
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001466 maxHeight += mPaddingTop + mPaddingBottom;
1467
1468 // Check against our minimum height
1469 maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001470
Dianne Hackborn189ee182010-12-02 21:48:53 -08001471 setMeasuredDimension(widthSizeAndState | (childState&MEASURED_STATE_MASK),
1472 resolveSizeAndState(maxHeight, heightMeasureSpec,
1473 (childState<<MEASURED_HEIGHT_STATE_SHIFT)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001474
1475 if (matchHeight) {
1476 forceUniformHeight(count, widthMeasureSpec);
1477 }
1478 }
1479
1480 private void forceUniformHeight(int count, int widthMeasureSpec) {
1481 // Pretend that the linear layout has an exact size. This is the measured height of
1482 // ourselves. The measured height should be the max height of the children, changed
Fabrice Di Megliofc53e582012-10-25 11:45:04 -07001483 // to accommodate the heightMeasureSpec from the parent
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001484 int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(),
1485 MeasureSpec.EXACTLY);
1486 for (int i = 0; i < count; ++i) {
1487 final View child = getVirtualChildAt(i);
Alan Viverettead526932015-12-17 12:42:39 -05001488 if (child != null && child.getVisibility() != GONE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001490
Romain Guy980a9382010-01-08 15:06:28 -08001491 if (lp.height == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001492 // Temporarily force children to reuse their old measured width
1493 // FIXME: this may not be right for something like wrapping text?
1494 int oldWidth = lp.width;
1495 lp.width = child.getMeasuredWidth();
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001496
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001497 // Remeasure with new dimensions
1498 measureChildWithMargins(child, widthMeasureSpec, 0, uniformMeasureSpec, 0);
1499 lp.width = oldWidth;
1500 }
1501 }
1502 }
1503 }
1504
1505 /**
1506 * <p>Returns the number of children to skip after measuring/laying out
1507 * the specified child.</p>
1508 *
1509 * @param child the child after which we want to skip children
1510 * @param index the index of the child after which we want to skip children
1511 * @return the number of children to skip, 0 by default
1512 */
1513 int getChildrenSkipCount(View child, int index) {
1514 return 0;
1515 }
1516
1517 /**
1518 * <p>Returns the size (width or height) that should be occupied by a null
1519 * child.</p>
1520 *
1521 * @param childIndex the index of the null child
1522 * @return the width or height of the child depending on the orientation
1523 */
1524 int measureNullChild(int childIndex) {
1525 return 0;
1526 }
1527
1528 /**
1529 * <p>Measure the child according to the parent's measure specs. This
1530 * method should be overriden by subclasses to force the sizing of
1531 * children. This method is called by {@link #measureVertical(int, int)} and
1532 * {@link #measureHorizontal(int, int)}.</p>
1533 *
1534 * @param child the child to measure
1535 * @param childIndex the index of the child in this view
1536 * @param widthMeasureSpec horizontal space requirements as imposed by the parent
1537 * @param totalWidth extra space that has been used up by the parent horizontally
1538 * @param heightMeasureSpec vertical space requirements as imposed by the parent
1539 * @param totalHeight extra space that has been used up by the parent vertically
1540 */
1541 void measureChildBeforeLayout(View child, int childIndex,
1542 int widthMeasureSpec, int totalWidth, int heightMeasureSpec,
1543 int totalHeight) {
1544 measureChildWithMargins(child, widthMeasureSpec, totalWidth,
1545 heightMeasureSpec, totalHeight);
1546 }
1547
1548 /**
1549 * <p>Return the location offset of the specified child. This can be used
1550 * by subclasses to change the location of a given widget.</p>
1551 *
1552 * @param child the child for which to obtain the location offset
1553 * @return the location offset in pixels
1554 */
1555 int getLocationOffset(View child) {
1556 return 0;
1557 }
1558
1559 /**
1560 * <p>Return the size offset of the next sibling of the specified child.
1561 * This can be used by subclasses to change the location of the widget
1562 * following <code>child</code>.</p>
1563 *
1564 * @param child the child whose next sibling will be moved
1565 * @return the location offset of the next child in pixels
1566 */
1567 int getNextLocationOffset(View child) {
1568 return 0;
1569 }
1570
1571 @Override
1572 protected void onLayout(boolean changed, int l, int t, int r, int b) {
1573 if (mOrientation == VERTICAL) {
Philip Milnead365cc2012-09-27 14:38:46 -07001574 layoutVertical(l, t, r, b);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001575 } else {
Philip Milnead365cc2012-09-27 14:38:46 -07001576 layoutHorizontal(l, t, r, b);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001577 }
1578 }
1579
1580 /**
1581 * Position the children during a layout pass if the orientation of this
1582 * LinearLayout is set to {@link #VERTICAL}.
1583 *
1584 * @see #getOrientation()
1585 * @see #setOrientation(int)
1586 * @see #onLayout(boolean, int, int, int, int)
Philip Milnead365cc2012-09-27 14:38:46 -07001587 * @param left
1588 * @param top
1589 * @param right
1590 * @param bottom
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001591 */
Philip Milnead365cc2012-09-27 14:38:46 -07001592 void layoutVertical(int left, int top, int right, int bottom) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001593 final int paddingLeft = mPaddingLeft;
1594
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001595 int childTop;
Romain Guy5b1b2412010-01-21 19:09:51 -08001596 int childLeft;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001597
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001598 // Where right end of child should go
Philip Milnead365cc2012-09-27 14:38:46 -07001599 final int width = right - left;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001600 int childRight = width - mPaddingRight;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001601
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001602 // Space available for child
1603 int childSpace = width - paddingLeft - mPaddingRight;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001604
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001605 final int count = getVirtualChildCount();
1606
1607 final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
Fabrice Di Meglio6a036402011-05-23 14:43:23 -07001608 final int minorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001609
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001610 switch (majorGravity) {
1611 case Gravity.BOTTOM:
1612 // mTotalLength contains the padding already
Philip Milnead365cc2012-09-27 14:38:46 -07001613 childTop = mPaddingTop + bottom - top - mTotalLength;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001614 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001615
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001616 // mTotalLength contains the padding already
1617 case Gravity.CENTER_VERTICAL:
Philip Milnead365cc2012-09-27 14:38:46 -07001618 childTop = mPaddingTop + (bottom - top - mTotalLength) / 2;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001619 break;
1620
1621 case Gravity.TOP:
1622 default:
1623 childTop = mPaddingTop;
1624 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001625 }
Adam Powellfcca00a2010-11-30 21:26:29 -08001626
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001627 for (int i = 0; i < count; i++) {
1628 final View child = getVirtualChildAt(i);
1629 if (child == null) {
1630 childTop += measureNullChild(i);
1631 } else if (child.getVisibility() != GONE) {
1632 final int childWidth = child.getMeasuredWidth();
1633 final int childHeight = child.getMeasuredHeight();
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001635 final LinearLayout.LayoutParams lp =
1636 (LinearLayout.LayoutParams) child.getLayoutParams();
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001637
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001638 int gravity = lp.gravity;
1639 if (gravity < 0) {
1640 gravity = minorGravity;
1641 }
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07001642 final int layoutDirection = getLayoutDirection();
Fabrice Di Meglioc0053222011-06-13 12:16:51 -07001643 final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
Fabrice Di Megliode35cee2011-06-01 15:13:50 -07001644 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001645 case Gravity.CENTER_HORIZONTAL:
1646 childLeft = paddingLeft + ((childSpace - childWidth) / 2)
1647 + lp.leftMargin - lp.rightMargin;
1648 break;
1649
1650 case Gravity.RIGHT:
1651 childLeft = childRight - childWidth - lp.rightMargin;
1652 break;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001653
1654 case Gravity.LEFT:
Romain Guy611cd3f2009-12-15 12:00:37 -08001655 default:
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001656 childLeft = paddingLeft + lp.leftMargin;
Romain Guy611cd3f2009-12-15 12:00:37 -08001657 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001658 }
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001659
Adam Powell696cba52011-03-29 10:38:16 -07001660 if (hasDividerBeforeChildAt(i)) {
1661 childTop += mDividerHeight;
1662 }
1663
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001664 childTop += lp.topMargin;
1665 setChildFrame(child, childLeft, childTop + getLocationOffset(child),
1666 childWidth, childHeight);
1667 childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);
1668
1669 i += getChildrenSkipCount(child, i);
1670 }
1671 }
1672 }
1673
Selim Cinek78528b22015-06-02 17:33:09 +02001674 @Override
1675 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) {
1676 super.onRtlPropertiesChanged(layoutDirection);
1677 if (layoutDirection != mLayoutDirection) {
1678 mLayoutDirection = layoutDirection;
1679 if (mOrientation == HORIZONTAL) {
1680 requestLayout();
1681 }
1682 }
1683 }
1684
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001685 /**
1686 * Position the children during a layout pass if the orientation of this
1687 * LinearLayout is set to {@link #HORIZONTAL}.
1688 *
1689 * @see #getOrientation()
1690 * @see #setOrientation(int)
1691 * @see #onLayout(boolean, int, int, int, int)
Philip Milnead365cc2012-09-27 14:38:46 -07001692 * @param left
1693 * @param top
1694 * @param right
1695 * @param bottom
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001696 */
Philip Milnead365cc2012-09-27 14:38:46 -07001697 void layoutHorizontal(int left, int top, int right, int bottom) {
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001698 final boolean isLayoutRtl = isLayoutRtl();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 final int paddingTop = mPaddingTop;
1700
Romain Guy5b1b2412010-01-21 19:09:51 -08001701 int childTop;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001702 int childLeft;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001703
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001704 // Where bottom of child should go
Philip Milnead365cc2012-09-27 14:38:46 -07001705 final int height = bottom - top;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001706 int childBottom = height - mPaddingBottom;
1707
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001708 // Space available for child
1709 int childSpace = height - paddingTop - mPaddingBottom;
1710
1711 final int count = getVirtualChildCount();
1712
Fabrice Di Meglio6a036402011-05-23 14:43:23 -07001713 final int majorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001714 final int minorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
1715
1716 final boolean baselineAligned = mBaselineAligned;
1717
1718 final int[] maxAscent = mMaxAscent;
1719 final int[] maxDescent = mMaxDescent;
1720
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07001721 final int layoutDirection = getLayoutDirection();
Fabrice Di Meglioc0053222011-06-13 12:16:51 -07001722 switch (Gravity.getAbsoluteGravity(majorGravity, layoutDirection)) {
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001723 case Gravity.RIGHT:
1724 // mTotalLength contains the padding already
Philip Milnead365cc2012-09-27 14:38:46 -07001725 childLeft = mPaddingLeft + right - left - mTotalLength;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001726 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001727
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001728 case Gravity.CENTER_HORIZONTAL:
1729 // mTotalLength contains the padding already
Philip Milnead365cc2012-09-27 14:38:46 -07001730 childLeft = mPaddingLeft + (right - left - mTotalLength) / 2;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001731 break;
1732
1733 case Gravity.LEFT:
1734 default:
1735 childLeft = mPaddingLeft;
1736 break;
1737 }
1738
1739 int start = 0;
1740 int dir = 1;
1741 //In case of RTL, start drawing from the last child.
1742 if (isLayoutRtl) {
1743 start = count - 1;
1744 dir = -1;
Adam Powellfcca00a2010-11-30 21:26:29 -08001745 }
1746
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001747 for (int i = 0; i < count; i++) {
Alan Viverettead526932015-12-17 12:42:39 -05001748 final int childIndex = start + dir * i;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001749 final View child = getVirtualChildAt(childIndex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 if (child == null) {
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001751 childLeft += measureNullChild(childIndex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001752 } else if (child.getVisibility() != GONE) {
1753 final int childWidth = child.getMeasuredWidth();
1754 final int childHeight = child.getMeasuredHeight();
1755 int childBaseline = -1;
1756
1757 final LinearLayout.LayoutParams lp =
1758 (LinearLayout.LayoutParams) child.getLayoutParams();
1759
Romain Guy980a9382010-01-08 15:06:28 -08001760 if (baselineAligned && lp.height != LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001761 childBaseline = child.getBaseline();
1762 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001763
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001764 int gravity = lp.gravity;
1765 if (gravity < 0) {
1766 gravity = minorGravity;
1767 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001768
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001769 switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
1770 case Gravity.TOP:
1771 childTop = paddingTop + lp.topMargin;
1772 if (childBaseline != -1) {
1773 childTop += maxAscent[INDEX_TOP] - childBaseline;
1774 }
1775 break;
1776
1777 case Gravity.CENTER_VERTICAL:
Romain Guy5b1b2412010-01-21 19:09:51 -08001778 // Removed support for baseline alignment when layout_gravity or
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001779 // gravity == center_vertical. See bug #1038483.
1780 // Keep the code around if we need to re-enable this feature
1781 // if (childBaseline != -1) {
1782 // // Align baselines vertically only if the child is smaller than us
1783 // if (childSpace - childHeight > 0) {
1784 // childTop = paddingTop + (childSpace / 2) - childBaseline;
1785 // } else {
1786 // childTop = paddingTop + (childSpace - childHeight) / 2;
1787 // }
1788 // } else {
1789 childTop = paddingTop + ((childSpace - childHeight) / 2)
1790 + lp.topMargin - lp.bottomMargin;
1791 break;
1792
1793 case Gravity.BOTTOM:
1794 childTop = childBottom - childHeight - lp.bottomMargin;
1795 if (childBaseline != -1) {
1796 int descent = child.getMeasuredHeight() - childBaseline;
1797 childTop -= (maxDescent[INDEX_BOTTOM] - descent);
1798 }
1799 break;
Romain Guy611cd3f2009-12-15 12:00:37 -08001800 default:
1801 childTop = paddingTop;
1802 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001803 }
1804
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001805 if (hasDividerBeforeChildAt(childIndex)) {
Adam Powell696cba52011-03-29 10:38:16 -07001806 childLeft += mDividerWidth;
1807 }
1808
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001809 childLeft += lp.leftMargin;
1810 setChildFrame(child, childLeft + getLocationOffset(child), childTop,
1811 childWidth, childHeight);
1812 childLeft += childWidth + lp.rightMargin +
1813 getNextLocationOffset(child);
1814
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001815 i += getChildrenSkipCount(child, childIndex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001816 }
1817 }
1818 }
1819
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001820 private void setChildFrame(View child, int left, int top, int width, int height) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001821 child.layout(left, top, left + width, top + height);
1822 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001823
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001824 /**
1825 * Should the layout be a column or a row.
Tor Norbyed9273d62013-05-30 15:59:53 -07001826 * @param orientation Pass {@link #HORIZONTAL} or {@link #VERTICAL}. Default
1827 * value is {@link #HORIZONTAL}.
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001828 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001829 * @attr ref android.R.styleable#LinearLayout_orientation
1830 */
Tor Norbyed9273d62013-05-30 15:59:53 -07001831 public void setOrientation(@OrientationMode int orientation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001832 if (mOrientation != orientation) {
1833 mOrientation = orientation;
1834 requestLayout();
1835 }
1836 }
1837
1838 /**
1839 * Returns the current orientation.
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001840 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001841 * @return either {@link #HORIZONTAL} or {@link #VERTICAL}
1842 */
Tor Norbyed9273d62013-05-30 15:59:53 -07001843 @OrientationMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001844 public int getOrientation() {
1845 return mOrientation;
1846 }
1847
1848 /**
1849 * Describes how the child views are positioned. Defaults to GRAVITY_TOP. If
1850 * this layout has a VERTICAL orientation, this controls where all the child
1851 * views are placed if there is extra vertical space. If this layout has a
1852 * HORIZONTAL orientation, this controls the alignment of the children.
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001853 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001854 * @param gravity See {@link android.view.Gravity}
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001855 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001856 * @attr ref android.R.styleable#LinearLayout_gravity
1857 */
1858 @android.view.RemotableViewMethod
1859 public void setGravity(int gravity) {
1860 if (mGravity != gravity) {
Fabrice Di Meglio6a036402011-05-23 14:43:23 -07001861 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
Fabrice Di Meglio9e3b0022011-06-06 16:30:29 -07001862 gravity |= Gravity.START;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001863 }
1864
1865 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
1866 gravity |= Gravity.TOP;
1867 }
1868
1869 mGravity = gravity;
1870 requestLayout();
1871 }
1872 }
1873
Jason Monkefe916c2016-01-20 10:46:12 -05001874 /**
1875 * Returns the current gravity. See {@link android.view.Gravity}
1876 *
1877 * @return the current gravity.
1878 * @see #setGravity
1879 */
1880 public int getGravity() {
1881 return mGravity;
1882 }
1883
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001884 @android.view.RemotableViewMethod
1885 public void setHorizontalGravity(int horizontalGravity) {
Fabrice Di Meglio6a036402011-05-23 14:43:23 -07001886 final int gravity = horizontalGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
1887 if ((mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) != gravity) {
1888 mGravity = (mGravity & ~Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) | gravity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001889 requestLayout();
1890 }
1891 }
1892
1893 @android.view.RemotableViewMethod
1894 public void setVerticalGravity(int verticalGravity) {
1895 final int gravity = verticalGravity & Gravity.VERTICAL_GRAVITY_MASK;
1896 if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != gravity) {
1897 mGravity = (mGravity & ~Gravity.VERTICAL_GRAVITY_MASK) | gravity;
1898 requestLayout();
1899 }
1900 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001901
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001902 @Override
1903 public LayoutParams generateLayoutParams(AttributeSet attrs) {
1904 return new LinearLayout.LayoutParams(getContext(), attrs);
1905 }
1906
1907 /**
1908 * Returns a set of layout parameters with a width of
Romain Guy980a9382010-01-08 15:06:28 -08001909 * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001910 * and a height of {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}
1911 * when the layout's orientation is {@link #VERTICAL}. When the orientation is
1912 * {@link #HORIZONTAL}, the width is set to {@link LayoutParams#WRAP_CONTENT}
1913 * and the height to {@link LayoutParams#WRAP_CONTENT}.
1914 */
1915 @Override
1916 protected LayoutParams generateDefaultLayoutParams() {
1917 if (mOrientation == HORIZONTAL) {
1918 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
1919 } else if (mOrientation == VERTICAL) {
Romain Guy980a9382010-01-08 15:06:28 -08001920 return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001921 }
1922 return null;
1923 }
1924
1925 @Override
Yigit Boyar885c50b2016-03-22 16:53:42 -07001926 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
Yigit Boyar2dd20a62016-08-01 17:42:28 -07001927 if (sPreserveMarginParamsInLayoutParamConversion) {
1928 if (lp instanceof LayoutParams) {
1929 return new LayoutParams((LayoutParams) lp);
1930 } else if (lp instanceof MarginLayoutParams) {
1931 return new LayoutParams((MarginLayoutParams) lp);
1932 }
Yigit Boyar885c50b2016-03-22 16:53:42 -07001933 }
Yigit Boyar2dd20a62016-08-01 17:42:28 -07001934 return new LayoutParams(lp);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001935 }
1936
1937
1938 // Override to allow type-checking of LayoutParams.
1939 @Override
1940 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
1941 return p instanceof LinearLayout.LayoutParams;
1942 }
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08001943
1944 @Override
Dianne Hackborna7bb6fb2015-02-03 18:13:40 -08001945 public CharSequence getAccessibilityClassName() {
1946 return LinearLayout.class.getName();
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08001947 }
1948
Siva Velusamy94a6d152015-05-05 15:07:00 -07001949 /** @hide */
1950 @Override
1951 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
1952 super.encodeProperties(encoder);
1953 encoder.addProperty("layout:baselineAligned", mBaselineAligned);
1954 encoder.addProperty("layout:baselineAlignedChildIndex", mBaselineAlignedChildIndex);
1955 encoder.addProperty("measurement:baselineChildTop", mBaselineChildTop);
1956 encoder.addProperty("measurement:orientation", mOrientation);
1957 encoder.addProperty("measurement:gravity", mGravity);
1958 encoder.addProperty("measurement:totalLength", mTotalLength);
1959 encoder.addProperty("layout:totalLength", mTotalLength);
1960 encoder.addProperty("layout:useLargestChild", mUseLargestChild);
1961 }
1962
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001963 /**
1964 * Per-child layout information associated with ViewLinearLayout.
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001965 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001966 * @attr ref android.R.styleable#LinearLayout_Layout_layout_weight
1967 * @attr ref android.R.styleable#LinearLayout_Layout_layout_gravity
1968 */
1969 public static class LayoutParams extends ViewGroup.MarginLayoutParams {
1970 /**
1971 * Indicates how much of the extra space in the LinearLayout will be
1972 * allocated to the view associated with these LayoutParams. Specify
1973 * 0 if the view should not be stretched. Otherwise the extra pixels
1974 * will be pro-rated among all views whose weight is greater than 0.
1975 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07001976 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001977 public float weight;
1978
1979 /**
1980 * Gravity for the view associated with these LayoutParams.
1981 *
1982 * @see android.view.Gravity
1983 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07001984 @ViewDebug.ExportedProperty(category = "layout", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001985 @ViewDebug.IntToString(from = -1, to = "NONE"),
1986 @ViewDebug.IntToString(from = Gravity.NO_GRAVITY, to = "NONE"),
1987 @ViewDebug.IntToString(from = Gravity.TOP, to = "TOP"),
1988 @ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"),
1989 @ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"),
1990 @ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"),
Chet Haase8b9ed442016-08-25 15:35:53 -07001991 @ViewDebug.IntToString(from = Gravity.START, to = "START"),
1992 @ViewDebug.IntToString(from = Gravity.END, to = "END"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001993 @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"),
1994 @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"),
1995 @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
1996 @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL, to = "FILL_HORIZONTAL"),
1997 @ViewDebug.IntToString(from = Gravity.CENTER, to = "CENTER"),
1998 @ViewDebug.IntToString(from = Gravity.FILL, to = "FILL")
1999 })
2000 public int gravity = -1;
2001
2002 /**
2003 * {@inheritDoc}
2004 */
2005 public LayoutParams(Context c, AttributeSet attrs) {
2006 super(c, attrs);
2007 TypedArray a =
2008 c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout_Layout);
2009
2010 weight = a.getFloat(com.android.internal.R.styleable.LinearLayout_Layout_layout_weight, 0);
2011 gravity = a.getInt(com.android.internal.R.styleable.LinearLayout_Layout_layout_gravity, -1);
2012
2013 a.recycle();
2014 }
2015
2016 /**
2017 * {@inheritDoc}
2018 */
2019 public LayoutParams(int width, int height) {
2020 super(width, height);
2021 weight = 0;
2022 }
2023
2024 /**
2025 * Creates a new set of layout parameters with the specified width, height
2026 * and weight.
2027 *
Romain Guy980a9382010-01-08 15:06:28 -08002028 * @param width the width, either {@link #MATCH_PARENT},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002029 * {@link #WRAP_CONTENT} or a fixed size in pixels
Romain Guy980a9382010-01-08 15:06:28 -08002030 * @param height the height, either {@link #MATCH_PARENT},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002031 * {@link #WRAP_CONTENT} or a fixed size in pixels
2032 * @param weight the weight
2033 */
2034 public LayoutParams(int width, int height, float weight) {
2035 super(width, height);
2036 this.weight = weight;
2037 }
2038
2039 /**
2040 * {@inheritDoc}
2041 */
2042 public LayoutParams(ViewGroup.LayoutParams p) {
2043 super(p);
2044 }
2045
2046 /**
2047 * {@inheritDoc}
2048 */
Alan Viverette0a0e1552013-08-07 13:24:09 -07002049 public LayoutParams(ViewGroup.MarginLayoutParams source) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002050 super(source);
2051 }
2052
Alan Viverette0a0e1552013-08-07 13:24:09 -07002053 /**
2054 * Copy constructor. Clones the width, height, margin values, weight,
2055 * and gravity of the source.
2056 *
2057 * @param source The layout params to copy from.
2058 */
2059 public LayoutParams(LayoutParams source) {
2060 super(source);
2061
2062 this.weight = source.weight;
2063 this.gravity = source.gravity;
2064 }
2065
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002066 @Override
2067 public String debug(String output) {
2068 return output + "LinearLayout.LayoutParams={width=" + sizeToString(width) +
2069 ", height=" + sizeToString(height) + " weight=" + weight + "}";
2070 }
Siva Velusamy94a6d152015-05-05 15:07:00 -07002071
2072 /** @hide */
2073 @Override
Mathew Inwooda85f4eb2018-08-21 16:08:34 +01002074 @UnsupportedAppUsage
Siva Velusamy94a6d152015-05-05 15:07:00 -07002075 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
2076 super.encodeProperties(encoder);
2077
2078 encoder.addProperty("layout:weight", weight);
2079 encoder.addProperty("layout:gravity", gravity);
2080 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002081 }
2082}