blob: bdde4352d69d8ea614d236d499c0ed0327e80cf9 [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;
Ashley Rose55f9f922019-01-28 19:29:36 -050034import android.view.inspector.InspectableProperty;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.widget.RemoteViews.RemoteView;
36
Aurimas Liutikas99441c52016-10-11 16:48:32 -070037import com.android.internal.R;
38
Tor Norbyed9273d62013-05-30 15:59:53 -070039import java.lang.annotation.Retention;
40import java.lang.annotation.RetentionPolicy;
41
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042
43/**
Joe Fernandezd9ffaa52017-04-25 23:39:17 -070044 * A layout that arranges other views either horizontally in a single column
45 * or vertically in a single row.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046 *
Joe Fernandezd9ffaa52017-04-25 23:39:17 -070047 * <p>The following snippet shows how to include a linear layout in your layout XML file:</p>
Scott Main41ec6532010-08-19 16:57:07 -070048 *
Joe Fernandezd9ffaa52017-04-25 23:39:17 -070049 * <pre>&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
50 * android:layout_width="match_parent"
51 * android:layout_height="match_parent"
52 * android:paddingLeft="16dp"
53 * android:paddingRight="16dp"
54 * android:orientation="horizontal"
55 * android:gravity="center"&gt;
56 *
57 * &lt;!-- Include other widget or layout tags here. These are considered
58 * "child views" or "children" of the linear layout --&gt;
59 *
60 * &lt;/LinearLayout&gt;</pre>
61 *
62 * <p>Set {@link android.R.styleable#LinearLayout_orientation android:orientation} to specify
63 * whether child views are displayed in a row or column.</p>
64 *
65 * <p>To control how linear layout aligns all the views it contains, set a value for
66 * {@link android.R.styleable#LinearLayout_gravity android:gravity}. For example, the
67 * snippet above sets android:gravity to "center". The value you set affects
68 * both horizontal and vertical alignment of all child views within the single row or column.</p>
69 *
70 * <p>You can set
Jeff Sharkey67f9d502017-08-05 13:49:13 -060071 * {@link android.R.styleable#LinearLayout_Layout_layout_weight android:layout_weight}
Joe Fernandezd9ffaa52017-04-25 23:39:17 -070072 * on individual child views to specify how linear layout divides remaining space amongst
73 * the views it contains. See the
74 * <a href="https://developer.android.com/guide/topics/ui/layout/linear.html">Linear Layout</a>
75 * guide for an example.</p>
76 *
77 * <p>See
78 * {@link android.widget.LinearLayout.LayoutParams LinearLayout.LayoutParams}
79 * to learn about other attributes you can set on a child view to affect its
80 * position and size in the containing linear layout.</p>
Romain Guy9295ada2010-06-15 11:33:24 -070081 *
82 * @attr ref android.R.styleable#LinearLayout_baselineAligned
83 * @attr ref android.R.styleable#LinearLayout_baselineAlignedChildIndex
84 * @attr ref android.R.styleable#LinearLayout_gravity
85 * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
86 * @attr ref android.R.styleable#LinearLayout_orientation
87 * @attr ref android.R.styleable#LinearLayout_weightSum
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 */
89@RemoteView
90public class LinearLayout extends ViewGroup {
Tor Norbyed9273d62013-05-30 15:59:53 -070091 /** @hide */
92 @IntDef({HORIZONTAL, VERTICAL})
93 @Retention(RetentionPolicy.SOURCE)
94 public @interface OrientationMode {}
95
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 public static final int HORIZONTAL = 0;
97 public static final int VERTICAL = 1;
98
Tor Norbyed9273d62013-05-30 15:59:53 -070099 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700100 @IntDef(flag = true, prefix = { "SHOW_DIVIDER_" }, value = {
101 SHOW_DIVIDER_NONE,
102 SHOW_DIVIDER_BEGINNING,
103 SHOW_DIVIDER_MIDDLE,
104 SHOW_DIVIDER_END
105 })
Tor Norbyed9273d62013-05-30 15:59:53 -0700106 @Retention(RetentionPolicy.SOURCE)
107 public @interface DividerMode {}
108
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109 /**
Adam Powellfcca00a2010-11-30 21:26:29 -0800110 * Don't show any dividers.
111 */
112 public static final int SHOW_DIVIDER_NONE = 0;
113 /**
114 * Show a divider at the beginning of the group.
115 */
116 public static final int SHOW_DIVIDER_BEGINNING = 1;
117 /**
118 * Show dividers between each item in the group.
119 */
120 public static final int SHOW_DIVIDER_MIDDLE = 2;
121 /**
122 * Show a divider at the end of the group.
123 */
124 public static final int SHOW_DIVIDER_END = 4;
125
126 /**
Alan Viverette40e1df32015-08-25 16:50:27 -0400127 * Compatibility check. Old versions of the platform would give different
128 * results from measurement passes using EXACTLY and non-EXACTLY modes,
129 * even when the resulting size was the same.
130 */
131 private final boolean mAllowInconsistentMeasurement;
132
133 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 * Whether the children of this layout are baseline aligned. Only applicable
135 * if {@link #mOrientation} is horizontal.
136 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700137 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 private boolean mBaselineAligned = true;
139
140 /**
141 * If this layout is part of another layout that is baseline aligned,
142 * use the child at this index as the baseline.
143 *
144 * Note: this is orthogonal to {@link #mBaselineAligned}, which is concerned
145 * with whether the children of this layout are baseline aligned.
146 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700147 @ViewDebug.ExportedProperty(category = "layout")
Karl Rosaenc1f9c402009-08-12 17:18:33 -0700148 private int mBaselineAlignedChildIndex = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149
150 /**
151 * The additional offset to the child's baseline.
152 * We'll calculate the baseline of this layout as we measure vertically; for
153 * horizontal linear layouts, the offset of 0 is appropriate.
154 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700155 @ViewDebug.ExportedProperty(category = "measurement")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 private int mBaselineChildTop = 0;
157
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700158 @ViewDebug.ExportedProperty(category = "measurement")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 private int mOrientation;
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700160
Fabrice Di Megliobce84d22011-06-02 15:57:01 -0700161 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = {
162 @ViewDebug.FlagToString(mask = -1,
163 equals = -1, name = "NONE"),
164 @ViewDebug.FlagToString(mask = Gravity.NO_GRAVITY,
165 equals = Gravity.NO_GRAVITY,name = "NONE"),
166 @ViewDebug.FlagToString(mask = Gravity.TOP,
167 equals = Gravity.TOP, name = "TOP"),
168 @ViewDebug.FlagToString(mask = Gravity.BOTTOM,
169 equals = Gravity.BOTTOM, name = "BOTTOM"),
170 @ViewDebug.FlagToString(mask = Gravity.LEFT,
171 equals = Gravity.LEFT, name = "LEFT"),
172 @ViewDebug.FlagToString(mask = Gravity.RIGHT,
173 equals = Gravity.RIGHT, name = "RIGHT"),
Fabrice Di Meglio9e3b0022011-06-06 16:30:29 -0700174 @ViewDebug.FlagToString(mask = Gravity.START,
175 equals = Gravity.START, name = "START"),
176 @ViewDebug.FlagToString(mask = Gravity.END,
177 equals = Gravity.END, name = "END"),
Fabrice Di Megliobce84d22011-06-02 15:57:01 -0700178 @ViewDebug.FlagToString(mask = Gravity.CENTER_VERTICAL,
179 equals = Gravity.CENTER_VERTICAL, name = "CENTER_VERTICAL"),
180 @ViewDebug.FlagToString(mask = Gravity.FILL_VERTICAL,
181 equals = Gravity.FILL_VERTICAL, name = "FILL_VERTICAL"),
182 @ViewDebug.FlagToString(mask = Gravity.CENTER_HORIZONTAL,
183 equals = Gravity.CENTER_HORIZONTAL, name = "CENTER_HORIZONTAL"),
184 @ViewDebug.FlagToString(mask = Gravity.FILL_HORIZONTAL,
185 equals = Gravity.FILL_HORIZONTAL, name = "FILL_HORIZONTAL"),
186 @ViewDebug.FlagToString(mask = Gravity.CENTER,
187 equals = Gravity.CENTER, name = "CENTER"),
188 @ViewDebug.FlagToString(mask = Gravity.FILL,
189 equals = Gravity.FILL, name = "FILL"),
Fabrice Di Meglioc46f7ff2011-06-06 18:23:10 -0700190 @ViewDebug.FlagToString(mask = Gravity.RELATIVE_LAYOUT_DIRECTION,
191 equals = Gravity.RELATIVE_LAYOUT_DIRECTION, name = "RELATIVE")
Jon Miranda4597e982014-07-29 07:25:49 -0700192 }, formatToHexString = true)
Clara Bayarri60368582018-11-22 15:13:52 +0000193 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
Fabrice Di Meglio9e3b0022011-06-06 16:30:29 -0700194 private int mGravity = Gravity.START | Gravity.TOP;
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700195
196 @ViewDebug.ExportedProperty(category = "measurement")
Mathew Inwooda85f4eb2018-08-21 16:08:34 +0100197 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 private int mTotalLength;
199
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700200 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 private float mWeightSum;
202
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700203 @ViewDebug.ExportedProperty(category = "layout")
Mathew Inwooda85f4eb2018-08-21 16:08:34 +0100204 @UnsupportedAppUsage
Romain Guy5b1b2412010-01-21 19:09:51 -0800205 private boolean mUseLargestChild;
206
Mathew Inwooda85f4eb2018-08-21 16:08:34 +0100207 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 private int[] mMaxAscent;
Mathew Inwooda85f4eb2018-08-21 16:08:34 +0100209 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 private int[] mMaxDescent;
211
212 private static final int VERTICAL_GRAVITY_COUNT = 4;
213
214 private static final int INDEX_CENTER_VERTICAL = 0;
Mathew Inwooda85f4eb2018-08-21 16:08:34 +0100215 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 private static final int INDEX_TOP = 1;
Mathew Inwooda85f4eb2018-08-21 16:08:34 +0100217 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 private static final int INDEX_BOTTOM = 2;
Romain Guy5b1b2412010-01-21 19:09:51 -0800219 private static final int INDEX_FILL = 3;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220
Mathew Inwooda85f4eb2018-08-21 16:08:34 +0100221 @UnsupportedAppUsage
Adam Powellfcca00a2010-11-30 21:26:29 -0800222 private Drawable mDivider;
223 private int mDividerWidth;
224 private int mDividerHeight;
225 private int mShowDividers;
226 private int mDividerPadding;
227
Selim Cinek78528b22015-06-02 17:33:09 +0200228 private int mLayoutDirection = View.LAYOUT_DIRECTION_UNDEFINED;
229
Chet Haasecb848882018-03-21 14:09:44 -0700230 /**
231 * Signals that compatibility booleans have been initialized according to
232 * target SDK versions.
233 */
234 private static boolean sCompatibilityDone = false;
235
236 /**
237 * Behavior change in P; always remeasure weighted children, regardless of excess space.
238 */
239 private static boolean sRemeasureWeightedChildren = true;
240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241 public LinearLayout(Context context) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700242 this(context, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 }
244
Scott Kennedy3a1fa102015-03-05 19:15:11 -0800245 public LinearLayout(Context context, @Nullable AttributeSet attrs) {
Romain Guy9295ada2010-06-15 11:33:24 -0700246 this(context, attrs, 0);
247 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700248
Scott Kennedy3a1fa102015-03-05 19:15:11 -0800249 public LinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
Alan Viverette617feb92013-09-09 18:09:13 -0700250 this(context, attrs, defStyleAttr, 0);
251 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252
Alan Viverette617feb92013-09-09 18:09:13 -0700253 public LinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
254 super(context, attrs, defStyleAttr, defStyleRes);
255
Chet Haasecb848882018-03-21 14:09:44 -0700256 if (!sCompatibilityDone && context != null) {
257 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
258
259 // Older apps only remeasure non-zero children
260 sRemeasureWeightedChildren = targetSdkVersion >= Build.VERSION_CODES.P;
261
262 sCompatibilityDone = true;
263 }
264
Alan Viverette617feb92013-09-09 18:09:13 -0700265 final TypedArray a = context.obtainStyledAttributes(
266 attrs, com.android.internal.R.styleable.LinearLayout, defStyleAttr, defStyleRes);
Aurimas Liutikasab324cf2019-02-07 16:46:38 -0800267 saveAttributeDataForStyleable(context, com.android.internal.R.styleable.LinearLayout,
268 attrs, a, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269
270 int index = a.getInt(com.android.internal.R.styleable.LinearLayout_orientation, -1);
271 if (index >= 0) {
272 setOrientation(index);
273 }
274
275 index = a.getInt(com.android.internal.R.styleable.LinearLayout_gravity, -1);
276 if (index >= 0) {
277 setGravity(index);
278 }
279
280 boolean baselineAligned = a.getBoolean(R.styleable.LinearLayout_baselineAligned, true);
281 if (!baselineAligned) {
282 setBaselineAligned(baselineAligned);
283 }
284
285 mWeightSum = a.getFloat(R.styleable.LinearLayout_weightSum, -1.0f);
286
287 mBaselineAlignedChildIndex =
288 a.getInt(com.android.internal.R.styleable.LinearLayout_baselineAlignedChildIndex, -1);
289
Romain Guy9295ada2010-06-15 11:33:24 -0700290 mUseLargestChild = a.getBoolean(R.styleable.LinearLayout_measureWithLargestChild, false);
Romain Guy5b1b2412010-01-21 19:09:51 -0800291
Adam Powellfcca00a2010-11-30 21:26:29 -0800292 mShowDividers = a.getInt(R.styleable.LinearLayout_showDividers, SHOW_DIVIDER_NONE);
293 mDividerPadding = a.getDimensionPixelSize(R.styleable.LinearLayout_dividerPadding, 0);
Kirill Grouchnikov3218a4e2017-04-26 17:45:28 -0400294 setDividerDrawable(a.getDrawable(R.styleable.LinearLayout_divider));
Adam Powellfcca00a2010-11-30 21:26:29 -0800295
Alan Viverette40e1df32015-08-25 16:50:27 -0400296 final int version = context.getApplicationInfo().targetSdkVersion;
297 mAllowInconsistentMeasurement = version <= Build.VERSION_CODES.M;
298
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299 a.recycle();
300 }
301
302 /**
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400303 * Returns <code>true</code> if this layout is currently configured to show at least one
304 * divider.
305 */
306 private boolean isShowingDividers() {
307 return (mShowDividers != SHOW_DIVIDER_NONE) && (mDivider != null);
308 }
309
310 /**
Adam Powellfcca00a2010-11-30 21:26:29 -0800311 * Set how dividers should be shown between items in this layout
312 *
313 * @param showDividers One or more of {@link #SHOW_DIVIDER_BEGINNING},
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400314 * {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END}
315 * to show dividers, or {@link #SHOW_DIVIDER_NONE} to show no dividers.
Adam Powellfcca00a2010-11-30 21:26:29 -0800316 */
Tor Norbyed9273d62013-05-30 15:59:53 -0700317 public void setShowDividers(@DividerMode int showDividers) {
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400318 if (showDividers == mShowDividers) {
319 return;
Adam Powellfcca00a2010-11-30 21:26:29 -0800320 }
321 mShowDividers = showDividers;
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400322
323 setWillNotDraw(!isShowingDividers());
324 requestLayout();
Adam Powellfcca00a2010-11-30 21:26:29 -0800325 }
326
Patrick Dubroye0a799a2011-05-04 16:19:22 -0700327 @Override
328 public boolean shouldDelayChildPressedState() {
329 return false;
330 }
331
Adam Powellfcca00a2010-11-30 21:26:29 -0800332 /**
333 * @return A flag set indicating how dividers should be shown around items.
334 * @see #setShowDividers(int)
335 */
Tor Norbyed9273d62013-05-30 15:59:53 -0700336 @DividerMode
Adam Powellfcca00a2010-11-30 21:26:29 -0800337 public int getShowDividers() {
338 return mShowDividers;
339 }
340
341 /**
Philip Milne1018fb42012-03-13 12:00:04 -0700342 * @return the divider Drawable that will divide each item.
343 *
344 * @see #setDividerDrawable(Drawable)
345 *
346 * @attr ref android.R.styleable#LinearLayout_divider
347 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500348 @InspectableProperty(name = "divider")
Philip Milne1018fb42012-03-13 12:00:04 -0700349 public Drawable getDividerDrawable() {
350 return mDivider;
351 }
352
353 /**
Adam Powellfcca00a2010-11-30 21:26:29 -0800354 * Set a drawable to be used as a divider between items.
Philip Milne1018fb42012-03-13 12:00:04 -0700355 *
Adam Powellfcca00a2010-11-30 21:26:29 -0800356 * @param divider Drawable that will divide each item.
Philip Milne1018fb42012-03-13 12:00:04 -0700357 *
Adam Powellfcca00a2010-11-30 21:26:29 -0800358 * @see #setShowDividers(int)
Philip Milne1018fb42012-03-13 12:00:04 -0700359 *
360 * @attr ref android.R.styleable#LinearLayout_divider
Adam Powellfcca00a2010-11-30 21:26:29 -0800361 */
362 public void setDividerDrawable(Drawable divider) {
363 if (divider == mDivider) {
364 return;
365 }
366 mDivider = divider;
367 if (divider != null) {
368 mDividerWidth = divider.getIntrinsicWidth();
369 mDividerHeight = divider.getIntrinsicHeight();
370 } else {
371 mDividerWidth = 0;
372 mDividerHeight = 0;
373 }
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400374
375 setWillNotDraw(!isShowingDividers());
Adam Powellfcca00a2010-11-30 21:26:29 -0800376 requestLayout();
377 }
378
Adam Powell696cba52011-03-29 10:38:16 -0700379 /**
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400380 * Set padding displayed on both ends of dividers. For a vertical layout, the padding is applied
381 * to left and right end of dividers. For a horizontal layout, the padding is applied to top and
382 * bottom end of dividers.
Adam Powell696cba52011-03-29 10:38:16 -0700383 *
384 * @param padding Padding value in pixels that will be applied to each end
385 *
386 * @see #setShowDividers(int)
387 * @see #setDividerDrawable(Drawable)
388 * @see #getDividerPadding()
389 */
390 public void setDividerPadding(int padding) {
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400391 if (padding == mDividerPadding) {
392 return;
393 }
Adam Powell696cba52011-03-29 10:38:16 -0700394 mDividerPadding = padding;
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400395
396 if (isShowingDividers()) {
397 requestLayout();
398 invalidate();
399 }
Adam Powell696cba52011-03-29 10:38:16 -0700400 }
401
402 /**
403 * Get the padding size used to inset dividers in pixels
404 *
405 * @see #setShowDividers(int)
406 * @see #setDividerDrawable(Drawable)
407 * @see #setDividerPadding(int)
408 */
409 public int getDividerPadding() {
410 return mDividerPadding;
411 }
412
Adam Powell640a66e2011-04-29 10:18:53 -0700413 /**
414 * Get the width of the current divider drawable.
415 *
416 * @hide Used internally by framework.
417 */
418 public int getDividerWidth() {
419 return mDividerWidth;
420 }
421
Adam Powellfcca00a2010-11-30 21:26:29 -0800422 @Override
423 protected void onDraw(Canvas canvas) {
424 if (mDivider == null) {
425 return;
426 }
427
428 if (mOrientation == VERTICAL) {
429 drawDividersVertical(canvas);
430 } else {
431 drawDividersHorizontal(canvas);
432 }
433 }
434
435 void drawDividersVertical(Canvas canvas) {
Adam Powellfcca00a2010-11-30 21:26:29 -0800436 final int count = getVirtualChildCount();
Adam Powellfcca00a2010-11-30 21:26:29 -0800437 for (int i = 0; i < count; i++) {
438 final View child = getVirtualChildAt(i);
Adam Powell35aecd52011-07-01 13:43:49 -0700439 if (child != null && child.getVisibility() != GONE) {
Adam Powell696cba52011-03-29 10:38:16 -0700440 if (hasDividerBeforeChildAt(i)) {
Adam Powell35aecd52011-07-01 13:43:49 -0700441 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Vladimir Baryshnikov20761fc2012-01-17 14:59:48 -0800442 final int top = child.getTop() - lp.topMargin - mDividerHeight;
Adam Powellfcca00a2010-11-30 21:26:29 -0800443 drawHorizontalDivider(canvas, top);
Adam Powellfcca00a2010-11-30 21:26:29 -0800444 }
Adam Powellfcca00a2010-11-30 21:26:29 -0800445 }
446 }
447
Adam Powell696cba52011-03-29 10:38:16 -0700448 if (hasDividerBeforeChildAt(count)) {
Doris Liuec6a4cd2015-06-25 15:16:54 -0700449 final View child = getLastNonGoneChild();
Adam Powell35aecd52011-07-01 13:43:49 -0700450 int bottom = 0;
451 if (child == null) {
452 bottom = getHeight() - getPaddingBottom() - mDividerHeight;
453 } else {
454 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
455 bottom = child.getBottom() + lp.bottomMargin;
456 }
457 drawHorizontalDivider(canvas, bottom);
Adam Powellfcca00a2010-11-30 21:26:29 -0800458 }
459 }
460
Doris Liuec6a4cd2015-06-25 15:16:54 -0700461 /**
462 * Finds the last child that is not gone. The last child will be used as the reference for
463 * where the end divider should be drawn.
464 */
465 private View getLastNonGoneChild() {
466 for (int i = getVirtualChildCount() - 1; i >= 0; i--) {
Alan Viverettead526932015-12-17 12:42:39 -0500467 final View child = getVirtualChildAt(i);
Doris Liuec6a4cd2015-06-25 15:16:54 -0700468 if (child != null && child.getVisibility() != GONE) {
469 return child;
470 }
471 }
472 return null;
473 }
474
Adam Powellfcca00a2010-11-30 21:26:29 -0800475 void drawDividersHorizontal(Canvas canvas) {
Adam Powellfcca00a2010-11-30 21:26:29 -0800476 final int count = getVirtualChildCount();
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700477 final boolean isLayoutRtl = isLayoutRtl();
Adam Powellfcca00a2010-11-30 21:26:29 -0800478 for (int i = 0; i < count; i++) {
479 final View child = getVirtualChildAt(i);
Adam Powell35aecd52011-07-01 13:43:49 -0700480 if (child != null && child.getVisibility() != GONE) {
Adam Powell696cba52011-03-29 10:38:16 -0700481 if (hasDividerBeforeChildAt(i)) {
Adam Powell35aecd52011-07-01 13:43:49 -0700482 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700483 final int position;
484 if (isLayoutRtl) {
485 position = child.getRight() + lp.rightMargin;
486 } else {
487 position = child.getLeft() - lp.leftMargin - mDividerWidth;
488 }
489 drawVerticalDivider(canvas, position);
Adam Powellfcca00a2010-11-30 21:26:29 -0800490 }
Adam Powellfcca00a2010-11-30 21:26:29 -0800491 }
492 }
493
Adam Powell696cba52011-03-29 10:38:16 -0700494 if (hasDividerBeforeChildAt(count)) {
Doris Liuec6a4cd2015-06-25 15:16:54 -0700495 final View child = getLastNonGoneChild();
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700496 int position;
Adam Powell35aecd52011-07-01 13:43:49 -0700497 if (child == null) {
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700498 if (isLayoutRtl) {
499 position = getPaddingLeft();
500 } else {
501 position = getWidth() - getPaddingRight() - mDividerWidth;
502 }
Adam Powell35aecd52011-07-01 13:43:49 -0700503 } else {
504 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700505 if (isLayoutRtl) {
506 position = child.getLeft() - lp.leftMargin - mDividerWidth;
507 } else {
508 position = child.getRight() + lp.rightMargin;
509 }
Adam Powell35aecd52011-07-01 13:43:49 -0700510 }
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700511 drawVerticalDivider(canvas, position);
Adam Powellfcca00a2010-11-30 21:26:29 -0800512 }
513 }
514
515 void drawHorizontalDivider(Canvas canvas, int top) {
516 mDivider.setBounds(getPaddingLeft() + mDividerPadding, top,
517 getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);
518 mDivider.draw(canvas);
519 }
520
521 void drawVerticalDivider(Canvas canvas, int left) {
522 mDivider.setBounds(left, getPaddingTop() + mDividerPadding,
523 left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding);
524 mDivider.draw(canvas);
525 }
526
527 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 * <p>Indicates whether widgets contained within this layout are aligned
529 * on their baseline or not.</p>
530 *
531 * @return true when widgets are baseline-aligned, false otherwise
532 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500533 @InspectableProperty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 public boolean isBaselineAligned() {
535 return mBaselineAligned;
536 }
537
538 /**
539 * <p>Defines whether widgets contained in this layout are
540 * baseline-aligned or not.</p>
541 *
542 * @param baselineAligned true to align widgets on their baseline,
543 * false otherwise
544 *
545 * @attr ref android.R.styleable#LinearLayout_baselineAligned
546 */
547 @android.view.RemotableViewMethod
548 public void setBaselineAligned(boolean baselineAligned) {
549 mBaselineAligned = baselineAligned;
550 }
551
Romain Guy9295ada2010-06-15 11:33:24 -0700552 /**
553 * When true, all children with a weight will be considered having
554 * the minimum size of the largest child. If false, all children are
555 * measured normally.
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700556 *
Romain Guy9295ada2010-06-15 11:33:24 -0700557 * @return True to measure children with a weight using the minimum
558 * size of the largest child, false otherwise.
Philip Milne1018fb42012-03-13 12:00:04 -0700559 *
560 * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
Romain Guy9295ada2010-06-15 11:33:24 -0700561 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500562 @InspectableProperty(name = "measureWithLargestChild")
Romain Guy9295ada2010-06-15 11:33:24 -0700563 public boolean isMeasureWithLargestChildEnabled() {
564 return mUseLargestChild;
565 }
566
567 /**
568 * When set to true, all children with a weight will be considered having
569 * the minimum size of the largest child. If false, all children are
570 * measured normally.
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700571 *
Romain Guy9295ada2010-06-15 11:33:24 -0700572 * Disabled by default.
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700573 *
Romain Guy9295ada2010-06-15 11:33:24 -0700574 * @param enabled True to measure children with a weight using the
575 * minimum size of the largest child, false otherwise.
Philip Milne1018fb42012-03-13 12:00:04 -0700576 *
577 * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
Romain Guy9295ada2010-06-15 11:33:24 -0700578 */
579 @android.view.RemotableViewMethod
580 public void setMeasureWithLargestChildEnabled(boolean enabled) {
581 mUseLargestChild = enabled;
582 }
583
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 @Override
585 public int getBaseline() {
586 if (mBaselineAlignedChildIndex < 0) {
587 return super.getBaseline();
588 }
589
590 if (getChildCount() <= mBaselineAlignedChildIndex) {
591 throw new RuntimeException("mBaselineAlignedChildIndex of LinearLayout "
592 + "set to an index that is out of bounds.");
593 }
594
595 final View child = getChildAt(mBaselineAlignedChildIndex);
596 final int childBaseline = child.getBaseline();
597
598 if (childBaseline == -1) {
599 if (mBaselineAlignedChildIndex == 0) {
600 // this is just the default case, safe to return -1
601 return -1;
602 }
603 // the user picked an index that points to something that doesn't
604 // know how to calculate its baseline.
605 throw new RuntimeException("mBaselineAlignedChildIndex of LinearLayout "
606 + "points to a View that doesn't know how to get its baseline.");
607 }
608
609 // TODO: This should try to take into account the virtual offsets
610 // (See getNextLocationOffset and getLocationOffset)
611 // We should add to childTop:
612 // sum([getNextLocationOffset(getChildAt(i)) / i < mBaselineAlignedChildIndex])
613 // and also add:
614 // getLocationOffset(child)
615 int childTop = mBaselineChildTop;
616
617 if (mOrientation == VERTICAL) {
618 final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
619 if (majorGravity != Gravity.TOP) {
620 switch (majorGravity) {
621 case Gravity.BOTTOM:
622 childTop = mBottom - mTop - mPaddingBottom - mTotalLength;
623 break;
624
625 case Gravity.CENTER_VERTICAL:
626 childTop += ((mBottom - mTop - mPaddingTop - mPaddingBottom) -
627 mTotalLength) / 2;
628 break;
629 }
630 }
631 }
632
633 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
634 return childTop + lp.topMargin + childBaseline;
635 }
636
637 /**
638 * @return The index of the child that will be used if this layout is
639 * part of a larger layout that is baseline aligned, or -1 if none has
640 * been set.
641 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500642 @InspectableProperty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 public int getBaselineAlignedChildIndex() {
644 return mBaselineAlignedChildIndex;
645 }
646
647 /**
648 * @param i The index of the child that will be used if this layout is
649 * part of a larger layout that is baseline aligned.
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700650 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651 * @attr ref android.R.styleable#LinearLayout_baselineAlignedChildIndex
652 */
653 @android.view.RemotableViewMethod
654 public void setBaselineAlignedChildIndex(int i) {
655 if ((i < 0) || (i >= getChildCount())) {
656 throw new IllegalArgumentException("base aligned child index out "
657 + "of range (0, " + getChildCount() + ")");
658 }
659 mBaselineAlignedChildIndex = i;
660 }
661
662 /**
koprivadebd4ee2018-09-13 10:59:46 -0700663 * <p>Returns the view at the specified index. This method can be overridden
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 * to take into account virtual children. Refer to
665 * {@link android.widget.TableLayout} and {@link android.widget.TableRow}
666 * for an example.</p>
667 *
668 * @param index the child's index
Alan Viverettead526932015-12-17 12:42:39 -0500669 * @return the child at the specified index, may be {@code null}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670 */
Alan Viverettead526932015-12-17 12:42:39 -0500671 @Nullable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672 View getVirtualChildAt(int index) {
673 return getChildAt(index);
674 }
675
676 /**
677 * <p>Returns the virtual number of children. This number might be different
678 * than the actual number of children if the layout can hold virtual
679 * children. Refer to
680 * {@link android.widget.TableLayout} and {@link android.widget.TableRow}
681 * for an example.</p>
682 *
683 * @return the virtual number of children
684 */
685 int getVirtualChildCount() {
686 return getChildCount();
687 }
688
689 /**
690 * Returns the desired weights sum.
691 *
692 * @return A number greater than 0.0f if the weight sum is defined, or
693 * a number lower than or equals to 0.0f if not weight sum is
694 * to be used.
695 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500696 @InspectableProperty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697 public float getWeightSum() {
698 return mWeightSum;
699 }
700
701 /**
702 * Defines the desired weights sum. If unspecified the weights sum is computed
703 * at layout time by adding the layout_weight of each child.
704 *
705 * This can be used for instance to give a single child 50% of the total
706 * available space by giving it a layout_weight of 0.5 and setting the
707 * weightSum to 1.0.
708 *
709 * @param weightSum a number greater than 0.0f, or a number lower than or equals
710 * to 0.0f if the weight sum should be computed from the children's
711 * layout_weight
712 */
713 @android.view.RemotableViewMethod
714 public void setWeightSum(float weightSum) {
715 mWeightSum = Math.max(0.0f, weightSum);
716 }
717
718 @Override
719 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
720 if (mOrientation == VERTICAL) {
721 measureVertical(widthMeasureSpec, heightMeasureSpec);
722 } else {
723 measureHorizontal(widthMeasureSpec, heightMeasureSpec);
724 }
725 }
726
727 /**
Adam Powell696cba52011-03-29 10:38:16 -0700728 * Determines where to position dividers between children.
729 *
730 * @param childIndex Index of child to check for preceding divider
731 * @return true if there should be a divider before the child at childIndex
732 * @hide Pending API consideration. Currently only used internally by the system.
733 */
734 protected boolean hasDividerBeforeChildAt(int childIndex) {
Doris Liuec6a4cd2015-06-25 15:16:54 -0700735 if (childIndex == getVirtualChildCount()) {
736 // Check whether the end divider should draw.
Adam Powell696cba52011-03-29 10:38:16 -0700737 return (mShowDividers & SHOW_DIVIDER_END) != 0;
Adam Powell696cba52011-03-29 10:38:16 -0700738 }
Doris Liuec6a4cd2015-06-25 15:16:54 -0700739 boolean allViewsAreGoneBefore = allViewsAreGoneBefore(childIndex);
740 if (allViewsAreGoneBefore) {
741 // This is the first view that's not gone, check if beginning divider is enabled.
742 return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0;
743 } else {
744 return (mShowDividers & SHOW_DIVIDER_MIDDLE) != 0;
745 }
746 }
747
748 /**
749 * Checks whether all (virtual) child views before the given index are gone.
750 */
751 private boolean allViewsAreGoneBefore(int childIndex) {
752 for (int i = childIndex - 1; i >= 0; i--) {
Alan Viverettead526932015-12-17 12:42:39 -0500753 final View child = getVirtualChildAt(i);
Doris Liuf102d422015-06-30 13:42:22 -0700754 if (child != null && child.getVisibility() != GONE) {
Doris Liuec6a4cd2015-06-25 15:16:54 -0700755 return false;
756 }
757 }
758 return true;
Adam Powell696cba52011-03-29 10:38:16 -0700759 }
760
761 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762 * Measures the children when the orientation of this LinearLayout is set
763 * to {@link #VERTICAL}.
764 *
765 * @param widthMeasureSpec Horizontal space requirements as imposed by the parent.
766 * @param heightMeasureSpec Vertical space requirements as imposed by the parent.
767 *
768 * @see #getOrientation()
769 * @see #setOrientation(int)
770 * @see #onMeasure(int, int)
771 */
772 void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
773 mTotalLength = 0;
774 int maxWidth = 0;
Dianne Hackborn189ee182010-12-02 21:48:53 -0800775 int childState = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 int alternativeMaxWidth = 0;
777 int weightedMaxWidth = 0;
778 boolean allFillParent = true;
779 float totalWeight = 0;
780
781 final int count = getVirtualChildCount();
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700782
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
784 final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
785
786 boolean matchWidth = false;
Alan Viverette65be9cc2014-02-24 18:21:09 -0800787 boolean skippedMeasure = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700789 final int baselineChildIndex = mBaselineAlignedChildIndex;
Romain Guy5b1b2412010-01-21 19:09:51 -0800790 final boolean useLargestChild = mUseLargestChild;
791
792 int largestChildHeight = Integer.MIN_VALUE;
Alan Viverette40e1df32015-08-25 16:50:27 -0400793 int consumedExcessSpace = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400795 int nonSkippedChildCount = 0;
796
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 // See how tall everyone is. Also remember max width.
798 for (int i = 0; i < count; ++i) {
799 final View child = getVirtualChildAt(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800 if (child == null) {
801 mTotalLength += measureNullChild(i);
802 continue;
803 }
804
805 if (child.getVisibility() == View.GONE) {
806 i += getChildrenSkipCount(child, i);
807 continue;
808 }
809
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400810 nonSkippedChildCount++;
Adam Powell696cba52011-03-29 10:38:16 -0700811 if (hasDividerBeforeChildAt(i)) {
Adam Powellfcca00a2010-11-30 21:26:29 -0800812 mTotalLength += mDividerHeight;
813 }
814
Alan Viverette40e1df32015-08-25 16:50:27 -0400815 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Alan Viverette61c41bf2016-05-05 17:52:10 +0000816
817 totalWeight += lp.weight;
Alan Viverette40e1df32015-08-25 16:50:27 -0400818
819 final boolean useExcessSpace = lp.height == 0 && lp.weight > 0;
820 if (heightMode == MeasureSpec.EXACTLY && useExcessSpace) {
821 // Optimization: don't bother measuring children who are only
822 // laid out using excess space. These views will get measured
823 // later if we have space to distribute.
Romain Guy053b4802010-02-05 15:34:33 -0800824 final int totalLength = mTotalLength;
825 mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);
Alan Viverette65be9cc2014-02-24 18:21:09 -0800826 skippedMeasure = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 } else {
Alan Viverette40e1df32015-08-25 16:50:27 -0400828 if (useExcessSpace) {
829 // The heightMode is either UNSPECIFIED or AT_MOST, and
830 // this child is only laid out using excess space. Measure
831 // using WRAP_CONTENT so that we can find out the view's
832 // optimal height. We'll restore the original height of 0
833 // after measurement.
Gilles Debunnef5c6eff2010-02-09 19:08:36 -0800834 lp.height = LayoutParams.WRAP_CONTENT;
Romain Guy5b1b2412010-01-21 19:09:51 -0800835 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836
Gilles Debunnef5c6eff2010-02-09 19:08:36 -0800837 // Determine how big this child would like to be. If this or
Romain Guy5b1b2412010-01-21 19:09:51 -0800838 // previous children have given a weight, then we allow it to
839 // use all available space (and we will shrink things later
840 // if needed).
Alan Viverette40e1df32015-08-25 16:50:27 -0400841 final int usedHeight = totalWeight == 0 ? mTotalLength : 0;
842 measureChildBeforeLayout(child, i, widthMeasureSpec, 0,
843 heightMeasureSpec, usedHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844
Alan Viverette5a969df2015-07-31 12:42:10 -0400845 final int childHeight = child.getMeasuredHeight();
Alan Viverette40e1df32015-08-25 16:50:27 -0400846 if (useExcessSpace) {
847 // Restore the original height and record how much space
848 // we've allocated to excess-only children so that we can
849 // match the behavior of EXACTLY measurement.
850 lp.height = 0;
851 consumedExcessSpace += childHeight;
852 }
853
Romain Guy053b4802010-02-05 15:34:33 -0800854 final int totalLength = mTotalLength;
855 mTotalLength = Math.max(totalLength, totalLength + childHeight + lp.topMargin +
856 lp.bottomMargin + getNextLocationOffset(child));
Romain Guy5b1b2412010-01-21 19:09:51 -0800857
858 if (useLargestChild) {
859 largestChildHeight = Math.max(childHeight, largestChildHeight);
860 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 }
862
863 /**
864 * If applicable, compute the additional offset to the child's baseline
865 * we'll need later when asked {@link #getBaseline}.
866 */
867 if ((baselineChildIndex >= 0) && (baselineChildIndex == i + 1)) {
868 mBaselineChildTop = mTotalLength;
869 }
870
871 // if we are trying to use a child index for our baseline, the above
872 // book keeping only works if there are no children above it with
873 // weight. fail fast to aid the developer.
874 if (i < baselineChildIndex && lp.weight > 0) {
875 throw new RuntimeException("A child of LinearLayout with index "
876 + "less than mBaselineAlignedChildIndex has weight > 0, which "
877 + "won't work. Either remove the weight, or don't set "
878 + "mBaselineAlignedChildIndex.");
879 }
880
881 boolean matchWidthLocally = false;
Romain Guy980a9382010-01-08 15:06:28 -0800882 if (widthMode != MeasureSpec.EXACTLY && lp.width == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 // The width of the linear layout will scale, and at least one
884 // child said it wanted to match our width. Set a flag
885 // indicating that we need to remeasure at least that view when
886 // we know our width.
887 matchWidth = true;
888 matchWidthLocally = true;
889 }
890
891 final int margin = lp.leftMargin + lp.rightMargin;
892 final int measuredWidth = child.getMeasuredWidth() + margin;
893 maxWidth = Math.max(maxWidth, measuredWidth);
Dianne Hackborn189ee182010-12-02 21:48:53 -0800894 childState = combineMeasuredStates(childState, child.getMeasuredState());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800895
Romain Guy980a9382010-01-08 15:06:28 -0800896 allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 if (lp.weight > 0) {
898 /*
899 * Widths of weighted Views are bogus if we end up
900 * remeasuring, so keep them separate.
901 */
902 weightedMaxWidth = Math.max(weightedMaxWidth,
903 matchWidthLocally ? margin : measuredWidth);
904 } else {
905 alternativeMaxWidth = Math.max(alternativeMaxWidth,
906 matchWidthLocally ? margin : measuredWidth);
907 }
908
909 i += getChildrenSkipCount(child, i);
910 }
Romain Guy5b1b2412010-01-21 19:09:51 -0800911
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400912 if (nonSkippedChildCount > 0 && hasDividerBeforeChildAt(count)) {
Adam Powellfcca00a2010-11-30 21:26:29 -0800913 mTotalLength += mDividerHeight;
914 }
915
Adam Powellf8ac6b72011-05-23 18:14:09 -0700916 if (useLargestChild &&
917 (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED)) {
Romain Guy5b1b2412010-01-21 19:09:51 -0800918 mTotalLength = 0;
919
920 for (int i = 0; i < count; ++i) {
921 final View child = getVirtualChildAt(i);
Romain Guy5b1b2412010-01-21 19:09:51 -0800922 if (child == null) {
923 mTotalLength += measureNullChild(i);
924 continue;
925 }
926
927 if (child.getVisibility() == GONE) {
928 i += getChildrenSkipCount(child, i);
929 continue;
930 }
931
932 final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
933 child.getLayoutParams();
Romain Guy053b4802010-02-05 15:34:33 -0800934 // Account for negative margins
935 final int totalLength = mTotalLength;
936 mTotalLength = Math.max(totalLength, totalLength + largestChildHeight +
937 lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));
Romain Guy5b1b2412010-01-21 19:09:51 -0800938 }
939 }
940
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 // Add in our padding
942 mTotalLength += mPaddingTop + mPaddingBottom;
943
944 int heightSize = mTotalLength;
945
946 // Check against our minimum height
947 heightSize = Math.max(heightSize, getSuggestedMinimumHeight());
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700948
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800949 // Reconcile our calculated size with the heightMeasureSpec
Dianne Hackborn189ee182010-12-02 21:48:53 -0800950 int heightSizeAndState = resolveSizeAndState(heightSize, heightMeasureSpec, 0);
951 heightSize = heightSizeAndState & MEASURED_SIZE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 // Either expand children with weight to take up available space or
Alan Viverette65be9cc2014-02-24 18:21:09 -0800953 // shrink them if they extend beyond our current bounds. If we skipped
954 // measurement on any children, we need to measure them now.
Alan Viverette918f8862016-03-17 12:28:31 -0400955 int remainingExcess = heightSize - mTotalLength
Alan Viverette40e1df32015-08-25 16:50:27 -0400956 + (mAllowInconsistentMeasurement ? 0 : consumedExcessSpace);
Chet Haasecb848882018-03-21 14:09:44 -0700957 if (skippedMeasure
958 || ((sRemeasureWeightedChildren || remainingExcess != 0) && totalWeight > 0.0f)) {
Alan Viverette918f8862016-03-17 12:28:31 -0400959 float remainingWeightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800960
961 mTotalLength = 0;
962
963 for (int i = 0; i < count; ++i) {
964 final View child = getVirtualChildAt(i);
Alan Viverette40e1df32015-08-25 16:50:27 -0400965 if (child == null || child.getVisibility() == View.GONE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800966 continue;
967 }
Alan Viverette40e1df32015-08-25 16:50:27 -0400968
969 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Alan Viverette918f8862016-03-17 12:28:31 -0400970 final float childWeight = lp.weight;
971 if (childWeight > 0) {
Alan Viverette61c41bf2016-05-05 17:52:10 +0000972 final int share = (int) (childWeight * remainingExcess / remainingWeightSum);
Alan Viverette918f8862016-03-17 12:28:31 -0400973 remainingExcess -= share;
974 remainingWeightSum -= childWeight;
975
Alan Viverette40e1df32015-08-25 16:50:27 -0400976 final int childHeight;
Alan Viverette070b22b2016-06-30 11:15:36 -0400977 if (mUseLargestChild && heightMode != MeasureSpec.EXACTLY) {
978 childHeight = largestChildHeight;
979 } else if (lp.height == 0 && (!mAllowInconsistentMeasurement
Alan Viverette40e1df32015-08-25 16:50:27 -0400980 || heightMode == MeasureSpec.EXACTLY)) {
981 // This child needs to be laid out from scratch using
982 // only its share of excess space.
983 childHeight = share;
Alan Viverette5a969df2015-07-31 12:42:10 -0400984 } else {
Alan Viverette40e1df32015-08-25 16:50:27 -0400985 // This child had some intrinsic height to which we
986 // need to add its share of excess space.
987 childHeight = child.getMeasuredHeight() + share;
Alan Viverette5a969df2015-07-31 12:42:10 -0400988 }
Dianne Hackborn189ee182010-12-02 21:48:53 -0800989
Alan Viverette40e1df32015-08-25 16:50:27 -0400990 final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
991 Math.max(0, childHeight), MeasureSpec.EXACTLY);
992 final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
993 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin,
994 lp.width);
995 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
996
Dianne Hackborn189ee182010-12-02 21:48:53 -0800997 // Child may now not fit in vertical dimension.
998 childState = combineMeasuredStates(childState, child.getMeasuredState()
999 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000 }
1001
1002 final int margin = lp.leftMargin + lp.rightMargin;
1003 final int measuredWidth = child.getMeasuredWidth() + margin;
1004 maxWidth = Math.max(maxWidth, measuredWidth);
1005
1006 boolean matchWidthLocally = widthMode != MeasureSpec.EXACTLY &&
Romain Guy980a9382010-01-08 15:06:28 -08001007 lp.width == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008
1009 alternativeMaxWidth = Math.max(alternativeMaxWidth,
1010 matchWidthLocally ? margin : measuredWidth);
1011
Romain Guy980a9382010-01-08 15:06:28 -08001012 allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001013
Romain Guy053b4802010-02-05 15:34:33 -08001014 final int totalLength = mTotalLength;
1015 mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredHeight() +
1016 lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 }
1018
1019 // Add in our padding
Romain Guy053b4802010-02-05 15:34:33 -08001020 mTotalLength += mPaddingTop + mPaddingBottom;
1021 // TODO: Should we recompute the heightSpec based on the new total length?
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001022 } else {
1023 alternativeMaxWidth = Math.max(alternativeMaxWidth,
1024 weightedMaxWidth);
Adam Powellf8ac6b72011-05-23 18:14:09 -07001025
1026
1027 // We have no limit, so make all weighted views as tall as the largest child.
1028 // Children will have already been measured once.
Adam Powelleabc9192012-05-04 14:49:46 -07001029 if (useLargestChild && heightMode != MeasureSpec.EXACTLY) {
Adam Powellf8ac6b72011-05-23 18:14:09 -07001030 for (int i = 0; i < count; i++) {
1031 final View child = getVirtualChildAt(i);
Adam Powellf8ac6b72011-05-23 18:14:09 -07001032 if (child == null || child.getVisibility() == View.GONE) {
1033 continue;
1034 }
1035
1036 final LinearLayout.LayoutParams lp =
1037 (LinearLayout.LayoutParams) child.getLayoutParams();
1038
1039 float childExtra = lp.weight;
1040 if (childExtra > 0) {
1041 child.measure(
1042 MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(),
1043 MeasureSpec.EXACTLY),
1044 MeasureSpec.makeMeasureSpec(largestChildHeight,
1045 MeasureSpec.EXACTLY));
1046 }
1047 }
1048 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049 }
1050
1051 if (!allFillParent && widthMode != MeasureSpec.EXACTLY) {
1052 maxWidth = alternativeMaxWidth;
1053 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001054
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 maxWidth += mPaddingLeft + mPaddingRight;
1056
1057 // Check against our minimum width
1058 maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001059
Dianne Hackborn189ee182010-12-02 21:48:53 -08001060 setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
1061 heightSizeAndState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001062
1063 if (matchWidth) {
1064 forceUniformWidth(count, heightMeasureSpec);
1065 }
1066 }
1067
1068 private void forceUniformWidth(int count, int heightMeasureSpec) {
1069 // Pretend that the linear layout has an exact size.
1070 int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(),
1071 MeasureSpec.EXACTLY);
1072 for (int i = 0; i< count; ++i) {
1073 final View child = getVirtualChildAt(i);
Alan Viverettead526932015-12-17 12:42:39 -05001074 if (child != null && child.getVisibility() != GONE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001075 LinearLayout.LayoutParams lp = ((LinearLayout.LayoutParams)child.getLayoutParams());
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001076
Romain Guy980a9382010-01-08 15:06:28 -08001077 if (lp.width == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001078 // Temporarily force children to reuse their old measured height
1079 // FIXME: this may not be right for something like wrapping text?
1080 int oldHeight = lp.height;
1081 lp.height = child.getMeasuredHeight();
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001082
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 // Remeasue with new dimensions
1084 measureChildWithMargins(child, uniformMeasureSpec, 0, heightMeasureSpec, 0);
1085 lp.height = oldHeight;
1086 }
1087 }
1088 }
1089 }
1090
1091 /**
1092 * Measures the children when the orientation of this LinearLayout is set
1093 * to {@link #HORIZONTAL}.
1094 *
1095 * @param widthMeasureSpec Horizontal space requirements as imposed by the parent.
1096 * @param heightMeasureSpec Vertical space requirements as imposed by the parent.
1097 *
1098 * @see #getOrientation()
1099 * @see #setOrientation(int)
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001100 * @see #onMeasure(int, int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 */
1102 void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec) {
1103 mTotalLength = 0;
1104 int maxHeight = 0;
Dianne Hackborn189ee182010-12-02 21:48:53 -08001105 int childState = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001106 int alternativeMaxHeight = 0;
1107 int weightedMaxHeight = 0;
1108 boolean allFillParent = true;
1109 float totalWeight = 0;
1110
1111 final int count = getVirtualChildCount();
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001113 final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
1114 final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
1115
1116 boolean matchHeight = false;
Alan Viverette65be9cc2014-02-24 18:21:09 -08001117 boolean skippedMeasure = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001118
1119 if (mMaxAscent == null || mMaxDescent == null) {
1120 mMaxAscent = new int[VERTICAL_GRAVITY_COUNT];
1121 mMaxDescent = new int[VERTICAL_GRAVITY_COUNT];
1122 }
1123
1124 final int[] maxAscent = mMaxAscent;
1125 final int[] maxDescent = mMaxDescent;
1126
1127 maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
1128 maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;
1129
1130 final boolean baselineAligned = mBaselineAligned;
Romain Guy5b1b2412010-01-21 19:09:51 -08001131 final boolean useLargestChild = mUseLargestChild;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001132
Romain Guyc3520902010-02-25 11:01:01 -08001133 final boolean isExactly = widthMode == MeasureSpec.EXACTLY;
Romain Guy5b1b2412010-01-21 19:09:51 -08001134
1135 int largestChildWidth = Integer.MIN_VALUE;
Alan Viverette40e1df32015-08-25 16:50:27 -04001136 int usedExcessSpace = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137
Kirill Grouchnikov9df08462016-04-26 15:28:25 -04001138 int nonSkippedChildCount = 0;
1139
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001140 // See how wide everyone is. Also remember max height.
1141 for (int i = 0; i < count; ++i) {
1142 final View child = getVirtualChildAt(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143 if (child == null) {
1144 mTotalLength += measureNullChild(i);
1145 continue;
1146 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148 if (child.getVisibility() == GONE) {
1149 i += getChildrenSkipCount(child, i);
1150 continue;
1151 }
1152
Kirill Grouchnikov9df08462016-04-26 15:28:25 -04001153 nonSkippedChildCount++;
Adam Powell696cba52011-03-29 10:38:16 -07001154 if (hasDividerBeforeChildAt(i)) {
Adam Powellfcca00a2010-11-30 21:26:29 -08001155 mTotalLength += mDividerWidth;
1156 }
1157
Alan Viverette40e1df32015-08-25 16:50:27 -04001158 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Alan Viverette61c41bf2016-05-05 17:52:10 +00001159
1160 totalWeight += lp.weight;
Alan Viverette40e1df32015-08-25 16:50:27 -04001161
1162 final boolean useExcessSpace = lp.width == 0 && lp.weight > 0;
1163 if (widthMode == MeasureSpec.EXACTLY && useExcessSpace) {
1164 // Optimization: don't bother measuring children who are only
1165 // laid out using excess space. These views will get measured
1166 // later if we have space to distribute.
Romain Guyc3520902010-02-25 11:01:01 -08001167 if (isExactly) {
1168 mTotalLength += lp.leftMargin + lp.rightMargin;
1169 } else {
1170 final int totalLength = mTotalLength;
1171 mTotalLength = Math.max(totalLength, totalLength +
1172 lp.leftMargin + lp.rightMargin);
1173 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174
1175 // Baseline alignment requires to measure widgets to obtain the
Romain Guy6c5664a2010-02-24 18:55:22 -08001176 // baseline offset (in particular for TextViews). The following
1177 // defeats the optimization mentioned above. Allow the child to
1178 // use as much space as it wants because we can shrink things
1179 // later (and re-measure).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 if (baselineAligned) {
Adam Powelld5dbf4b2015-06-11 13:19:24 -07001181 final int freeWidthSpec = MeasureSpec.makeSafeMeasureSpec(
Filip Gruszczynskib6824bf2015-04-13 09:16:25 -07001182 MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.UNSPECIFIED);
Adam Powelld5dbf4b2015-06-11 13:19:24 -07001183 final int freeHeightSpec = MeasureSpec.makeSafeMeasureSpec(
Filip Gruszczynskib6824bf2015-04-13 09:16:25 -07001184 MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED);
1185 child.measure(freeWidthSpec, freeHeightSpec);
Alan Viverette65be9cc2014-02-24 18:21:09 -08001186 } else {
1187 skippedMeasure = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001188 }
1189 } else {
Alan Viverette40e1df32015-08-25 16:50:27 -04001190 if (useExcessSpace) {
1191 // The widthMode is either UNSPECIFIED or AT_MOST, and
1192 // this child is only laid out using excess space. Measure
1193 // using WRAP_CONTENT so that we can find out the view's
1194 // optimal width. We'll restore the original width of 0
1195 // after measurement.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 lp.width = LayoutParams.WRAP_CONTENT;
1197 }
1198
1199 // Determine how big this child would like to be. If this or
1200 // previous children have given a weight, then we allow it to
1201 // use all available space (and we will shrink things later
1202 // if needed).
Alan Viverette40e1df32015-08-25 16:50:27 -04001203 final int usedWidth = totalWeight == 0 ? mTotalLength : 0;
1204 measureChildBeforeLayout(child, i, widthMeasureSpec, usedWidth,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001205 heightMeasureSpec, 0);
1206
Alan Viverette40e1df32015-08-25 16:50:27 -04001207 final int childWidth = child.getMeasuredWidth();
1208 if (useExcessSpace) {
1209 // Restore the original width and record how much space
1210 // we've allocated to excess-only children so that we can
1211 // match the behavior of EXACTLY measurement.
1212 lp.width = 0;
1213 usedExcessSpace += childWidth;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001214 }
Romain Guy5b1b2412010-01-21 19:09:51 -08001215
Romain Guyc3520902010-02-25 11:01:01 -08001216 if (isExactly) {
Alan Viverette40e1df32015-08-25 16:50:27 -04001217 mTotalLength += childWidth + lp.leftMargin + lp.rightMargin
1218 + getNextLocationOffset(child);
Romain Guyc3520902010-02-25 11:01:01 -08001219 } else {
1220 final int totalLength = mTotalLength;
Alan Viverette40e1df32015-08-25 16:50:27 -04001221 mTotalLength = Math.max(totalLength, totalLength + childWidth + lp.leftMargin
1222 + lp.rightMargin + getNextLocationOffset(child));
Romain Guyc3520902010-02-25 11:01:01 -08001223 }
Romain Guy5b1b2412010-01-21 19:09:51 -08001224
1225 if (useLargestChild) {
1226 largestChildWidth = Math.max(childWidth, largestChildWidth);
1227 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001228 }
1229
1230 boolean matchHeightLocally = false;
Romain Guy980a9382010-01-08 15:06:28 -08001231 if (heightMode != MeasureSpec.EXACTLY && lp.height == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001232 // The height of the linear layout will scale, and at least one
1233 // child said it wanted to match our height. Set a flag indicating that
1234 // we need to remeasure at least that view when we know our height.
1235 matchHeight = true;
1236 matchHeightLocally = true;
1237 }
1238
1239 final int margin = lp.topMargin + lp.bottomMargin;
1240 final int childHeight = child.getMeasuredHeight() + margin;
Dianne Hackborn189ee182010-12-02 21:48:53 -08001241 childState = combineMeasuredStates(childState, child.getMeasuredState());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001242
1243 if (baselineAligned) {
1244 final int childBaseline = child.getBaseline();
1245 if (childBaseline != -1) {
1246 // Translates the child's vertical gravity into an index
1247 // in the range 0..VERTICAL_GRAVITY_COUNT
1248 final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity)
1249 & Gravity.VERTICAL_GRAVITY_MASK;
1250 final int index = ((gravity >> Gravity.AXIS_Y_SHIFT)
1251 & ~Gravity.AXIS_SPECIFIED) >> 1;
1252
1253 maxAscent[index] = Math.max(maxAscent[index], childBaseline);
1254 maxDescent[index] = Math.max(maxDescent[index], childHeight - childBaseline);
1255 }
1256 }
1257
1258 maxHeight = Math.max(maxHeight, childHeight);
1259
Romain Guy980a9382010-01-08 15:06:28 -08001260 allFillParent = allFillParent && lp.height == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001261 if (lp.weight > 0) {
1262 /*
1263 * Heights of weighted Views are bogus if we end up
1264 * remeasuring, so keep them separate.
1265 */
1266 weightedMaxHeight = Math.max(weightedMaxHeight,
1267 matchHeightLocally ? margin : childHeight);
1268 } else {
1269 alternativeMaxHeight = Math.max(alternativeMaxHeight,
1270 matchHeightLocally ? margin : childHeight);
1271 }
1272
1273 i += getChildrenSkipCount(child, i);
1274 }
1275
Kirill Grouchnikov9df08462016-04-26 15:28:25 -04001276 if (nonSkippedChildCount > 0 && hasDividerBeforeChildAt(count)) {
Adam Powellfcca00a2010-11-30 21:26:29 -08001277 mTotalLength += mDividerWidth;
1278 }
1279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001280 // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP,
1281 // the most common case
1282 if (maxAscent[INDEX_TOP] != -1 ||
1283 maxAscent[INDEX_CENTER_VERTICAL] != -1 ||
1284 maxAscent[INDEX_BOTTOM] != -1 ||
1285 maxAscent[INDEX_FILL] != -1) {
1286 final int ascent = Math.max(maxAscent[INDEX_FILL],
1287 Math.max(maxAscent[INDEX_CENTER_VERTICAL],
1288 Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM])));
1289 final int descent = Math.max(maxDescent[INDEX_FILL],
1290 Math.max(maxDescent[INDEX_CENTER_VERTICAL],
1291 Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM])));
1292 maxHeight = Math.max(maxHeight, ascent + descent);
1293 }
1294
Adam Powellf8ac6b72011-05-23 18:14:09 -07001295 if (useLargestChild &&
1296 (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.UNSPECIFIED)) {
Romain Guy5b1b2412010-01-21 19:09:51 -08001297 mTotalLength = 0;
1298
1299 for (int i = 0; i < count; ++i) {
1300 final View child = getVirtualChildAt(i);
Romain Guy5b1b2412010-01-21 19:09:51 -08001301 if (child == null) {
1302 mTotalLength += measureNullChild(i);
1303 continue;
1304 }
1305
1306 if (child.getVisibility() == GONE) {
1307 i += getChildrenSkipCount(child, i);
1308 continue;
1309 }
1310
1311 final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
1312 child.getLayoutParams();
Romain Guyc3520902010-02-25 11:01:01 -08001313 if (isExactly) {
1314 mTotalLength += largestChildWidth + lp.leftMargin + lp.rightMargin +
1315 getNextLocationOffset(child);
1316 } else {
1317 final int totalLength = mTotalLength;
1318 mTotalLength = Math.max(totalLength, totalLength + largestChildWidth +
1319 lp.leftMargin + lp.rightMargin + getNextLocationOffset(child));
1320 }
Romain Guy5b1b2412010-01-21 19:09:51 -08001321 }
1322 }
1323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001324 // Add in our padding
1325 mTotalLength += mPaddingLeft + mPaddingRight;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001326
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001327 int widthSize = mTotalLength;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001329 // Check against our minimum width
1330 widthSize = Math.max(widthSize, getSuggestedMinimumWidth());
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001331
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001332 // Reconcile our calculated size with the widthMeasureSpec
Dianne Hackborn189ee182010-12-02 21:48:53 -08001333 int widthSizeAndState = resolveSizeAndState(widthSize, widthMeasureSpec, 0);
1334 widthSize = widthSizeAndState & MEASURED_SIZE_MASK;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001335
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001336 // Either expand children with weight to take up available space or
Alan Viverette65be9cc2014-02-24 18:21:09 -08001337 // shrink them if they extend beyond our current bounds. If we skipped
1338 // measurement on any children, we need to measure them now.
Alan Viverette918f8862016-03-17 12:28:31 -04001339 int remainingExcess = widthSize - mTotalLength
Alan Viverette40e1df32015-08-25 16:50:27 -04001340 + (mAllowInconsistentMeasurement ? 0 : usedExcessSpace);
Chet Haasecb848882018-03-21 14:09:44 -07001341 if (skippedMeasure
1342 || ((sRemeasureWeightedChildren || remainingExcess != 0) && totalWeight > 0.0f)) {
Alan Viverette918f8862016-03-17 12:28:31 -04001343 float remainingWeightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001344
1345 maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
1346 maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;
1347 maxHeight = -1;
1348
1349 mTotalLength = 0;
1350
1351 for (int i = 0; i < count; ++i) {
1352 final View child = getVirtualChildAt(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001353 if (child == null || child.getVisibility() == View.GONE) {
1354 continue;
1355 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001356
Alan Viverette40e1df32015-08-25 16:50:27 -04001357 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Alan Viverette918f8862016-03-17 12:28:31 -04001358 final float childWeight = lp.weight;
1359 if (childWeight > 0) {
Alan Viverette61c41bf2016-05-05 17:52:10 +00001360 final int share = (int) (childWeight * remainingExcess / remainingWeightSum);
Alan Viverette918f8862016-03-17 12:28:31 -04001361 remainingExcess -= share;
1362 remainingWeightSum -= childWeight;
1363
Alan Viverette40e1df32015-08-25 16:50:27 -04001364 final int childWidth;
Alan Viverette070b22b2016-06-30 11:15:36 -04001365 if (mUseLargestChild && widthMode != MeasureSpec.EXACTLY) {
1366 childWidth = largestChildWidth;
1367 } else if (lp.width == 0 && (!mAllowInconsistentMeasurement
Alan Viverette40e1df32015-08-25 16:50:27 -04001368 || widthMode == MeasureSpec.EXACTLY)) {
1369 // This child needs to be laid out from scratch using
1370 // only its share of excess space.
1371 childWidth = share;
1372 } else {
1373 // This child had some intrinsic width to which we
1374 // need to add its share of excess space.
1375 childWidth = child.getMeasuredWidth() + share;
1376 }
Alan Viverette5a969df2015-07-31 12:42:10 -04001377
Alan Viverette40e1df32015-08-25 16:50:27 -04001378 final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
1379 Math.max(0, childWidth), MeasureSpec.EXACTLY);
1380 final int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001381 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin,
1382 lp.height);
Alan Viverette40e1df32015-08-25 16:50:27 -04001383 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn189ee182010-12-02 21:48:53 -08001384
1385 // Child may now not fit in horizontal dimension.
1386 childState = combineMeasuredStates(childState,
1387 child.getMeasuredState() & MEASURED_STATE_MASK);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001388 }
1389
Romain Guyc3520902010-02-25 11:01:01 -08001390 if (isExactly) {
1391 mTotalLength += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin +
1392 getNextLocationOffset(child);
1393 } else {
1394 final int totalLength = mTotalLength;
1395 mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredWidth() +
1396 lp.leftMargin + lp.rightMargin + getNextLocationOffset(child));
1397 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398
1399 boolean matchHeightLocally = heightMode != MeasureSpec.EXACTLY &&
Romain Guy980a9382010-01-08 15:06:28 -08001400 lp.height == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401
1402 final int margin = lp.topMargin + lp .bottomMargin;
1403 int childHeight = child.getMeasuredHeight() + margin;
1404 maxHeight = Math.max(maxHeight, childHeight);
1405 alternativeMaxHeight = Math.max(alternativeMaxHeight,
1406 matchHeightLocally ? margin : childHeight);
1407
Romain Guy980a9382010-01-08 15:06:28 -08001408 allFillParent = allFillParent && lp.height == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001409
1410 if (baselineAligned) {
1411 final int childBaseline = child.getBaseline();
1412 if (childBaseline != -1) {
1413 // Translates the child's vertical gravity into an index in the range 0..2
1414 final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity)
1415 & Gravity.VERTICAL_GRAVITY_MASK;
1416 final int index = ((gravity >> Gravity.AXIS_Y_SHIFT)
1417 & ~Gravity.AXIS_SPECIFIED) >> 1;
1418
1419 maxAscent[index] = Math.max(maxAscent[index], childBaseline);
1420 maxDescent[index] = Math.max(maxDescent[index],
1421 childHeight - childBaseline);
1422 }
1423 }
1424 }
1425
1426 // Add in our padding
1427 mTotalLength += mPaddingLeft + mPaddingRight;
Romain Guy053b4802010-02-05 15:34:33 -08001428 // TODO: Should we update widthSize with the new total length?
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001429
1430 // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP,
1431 // the most common case
1432 if (maxAscent[INDEX_TOP] != -1 ||
1433 maxAscent[INDEX_CENTER_VERTICAL] != -1 ||
1434 maxAscent[INDEX_BOTTOM] != -1 ||
1435 maxAscent[INDEX_FILL] != -1) {
1436 final int ascent = Math.max(maxAscent[INDEX_FILL],
1437 Math.max(maxAscent[INDEX_CENTER_VERTICAL],
1438 Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM])));
1439 final int descent = Math.max(maxDescent[INDEX_FILL],
1440 Math.max(maxDescent[INDEX_CENTER_VERTICAL],
1441 Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM])));
1442 maxHeight = Math.max(maxHeight, ascent + descent);
1443 }
1444 } else {
1445 alternativeMaxHeight = Math.max(alternativeMaxHeight, weightedMaxHeight);
Adam Powellf8ac6b72011-05-23 18:14:09 -07001446
1447 // We have no limit, so make all weighted views as wide as the largest child.
1448 // Children will have already been measured once.
Adam Powelleabc9192012-05-04 14:49:46 -07001449 if (useLargestChild && widthMode != MeasureSpec.EXACTLY) {
Adam Powellf8ac6b72011-05-23 18:14:09 -07001450 for (int i = 0; i < count; i++) {
1451 final View child = getVirtualChildAt(i);
Adam Powellf8ac6b72011-05-23 18:14:09 -07001452 if (child == null || child.getVisibility() == View.GONE) {
1453 continue;
1454 }
1455
1456 final LinearLayout.LayoutParams lp =
1457 (LinearLayout.LayoutParams) child.getLayoutParams();
1458
1459 float childExtra = lp.weight;
1460 if (childExtra > 0) {
1461 child.measure(
1462 MeasureSpec.makeMeasureSpec(largestChildWidth, MeasureSpec.EXACTLY),
1463 MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(),
1464 MeasureSpec.EXACTLY));
1465 }
1466 }
1467 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 }
1469
1470 if (!allFillParent && heightMode != MeasureSpec.EXACTLY) {
1471 maxHeight = alternativeMaxHeight;
1472 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001473
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001474 maxHeight += mPaddingTop + mPaddingBottom;
1475
1476 // Check against our minimum height
1477 maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001478
Dianne Hackborn189ee182010-12-02 21:48:53 -08001479 setMeasuredDimension(widthSizeAndState | (childState&MEASURED_STATE_MASK),
1480 resolveSizeAndState(maxHeight, heightMeasureSpec,
1481 (childState<<MEASURED_HEIGHT_STATE_SHIFT)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001482
1483 if (matchHeight) {
1484 forceUniformHeight(count, widthMeasureSpec);
1485 }
1486 }
1487
1488 private void forceUniformHeight(int count, int widthMeasureSpec) {
1489 // Pretend that the linear layout has an exact size. This is the measured height of
1490 // ourselves. The measured height should be the max height of the children, changed
Fabrice Di Megliofc53e582012-10-25 11:45:04 -07001491 // to accommodate the heightMeasureSpec from the parent
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001492 int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(),
1493 MeasureSpec.EXACTLY);
1494 for (int i = 0; i < count; ++i) {
1495 final View child = getVirtualChildAt(i);
Alan Viverettead526932015-12-17 12:42:39 -05001496 if (child != null && child.getVisibility() != GONE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001497 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001498
Romain Guy980a9382010-01-08 15:06:28 -08001499 if (lp.height == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001500 // Temporarily force children to reuse their old measured width
1501 // FIXME: this may not be right for something like wrapping text?
1502 int oldWidth = lp.width;
1503 lp.width = child.getMeasuredWidth();
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001504
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001505 // Remeasure with new dimensions
1506 measureChildWithMargins(child, widthMeasureSpec, 0, uniformMeasureSpec, 0);
1507 lp.width = oldWidth;
1508 }
1509 }
1510 }
1511 }
1512
1513 /**
1514 * <p>Returns the number of children to skip after measuring/laying out
1515 * the specified child.</p>
1516 *
1517 * @param child the child after which we want to skip children
1518 * @param index the index of the child after which we want to skip children
1519 * @return the number of children to skip, 0 by default
1520 */
1521 int getChildrenSkipCount(View child, int index) {
1522 return 0;
1523 }
1524
1525 /**
1526 * <p>Returns the size (width or height) that should be occupied by a null
1527 * child.</p>
1528 *
1529 * @param childIndex the index of the null child
1530 * @return the width or height of the child depending on the orientation
1531 */
1532 int measureNullChild(int childIndex) {
1533 return 0;
1534 }
1535
1536 /**
1537 * <p>Measure the child according to the parent's measure specs. This
koprivadebd4ee2018-09-13 10:59:46 -07001538 * method should be overridden by subclasses to force the sizing of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001539 * children. This method is called by {@link #measureVertical(int, int)} and
1540 * {@link #measureHorizontal(int, int)}.</p>
1541 *
1542 * @param child the child to measure
1543 * @param childIndex the index of the child in this view
1544 * @param widthMeasureSpec horizontal space requirements as imposed by the parent
1545 * @param totalWidth extra space that has been used up by the parent horizontally
1546 * @param heightMeasureSpec vertical space requirements as imposed by the parent
1547 * @param totalHeight extra space that has been used up by the parent vertically
1548 */
1549 void measureChildBeforeLayout(View child, int childIndex,
1550 int widthMeasureSpec, int totalWidth, int heightMeasureSpec,
1551 int totalHeight) {
1552 measureChildWithMargins(child, widthMeasureSpec, totalWidth,
1553 heightMeasureSpec, totalHeight);
1554 }
1555
1556 /**
1557 * <p>Return the location offset of the specified child. This can be used
1558 * by subclasses to change the location of a given widget.</p>
1559 *
1560 * @param child the child for which to obtain the location offset
1561 * @return the location offset in pixels
1562 */
1563 int getLocationOffset(View child) {
1564 return 0;
1565 }
1566
1567 /**
1568 * <p>Return the size offset of the next sibling of the specified child.
1569 * This can be used by subclasses to change the location of the widget
1570 * following <code>child</code>.</p>
1571 *
1572 * @param child the child whose next sibling will be moved
1573 * @return the location offset of the next child in pixels
1574 */
1575 int getNextLocationOffset(View child) {
1576 return 0;
1577 }
1578
1579 @Override
1580 protected void onLayout(boolean changed, int l, int t, int r, int b) {
1581 if (mOrientation == VERTICAL) {
Philip Milnead365cc2012-09-27 14:38:46 -07001582 layoutVertical(l, t, r, b);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583 } else {
Philip Milnead365cc2012-09-27 14:38:46 -07001584 layoutHorizontal(l, t, r, b);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585 }
1586 }
1587
1588 /**
1589 * Position the children during a layout pass if the orientation of this
1590 * LinearLayout is set to {@link #VERTICAL}.
1591 *
1592 * @see #getOrientation()
1593 * @see #setOrientation(int)
1594 * @see #onLayout(boolean, int, int, int, int)
Philip Milnead365cc2012-09-27 14:38:46 -07001595 * @param left
1596 * @param top
1597 * @param right
1598 * @param bottom
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001599 */
Philip Milnead365cc2012-09-27 14:38:46 -07001600 void layoutVertical(int left, int top, int right, int bottom) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001601 final int paddingLeft = mPaddingLeft;
1602
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001603 int childTop;
Romain Guy5b1b2412010-01-21 19:09:51 -08001604 int childLeft;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001605
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001606 // Where right end of child should go
Philip Milnead365cc2012-09-27 14:38:46 -07001607 final int width = right - left;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001608 int childRight = width - mPaddingRight;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001609
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001610 // Space available for child
1611 int childSpace = width - paddingLeft - mPaddingRight;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001612
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001613 final int count = getVirtualChildCount();
1614
1615 final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
Fabrice Di Meglio6a036402011-05-23 14:43:23 -07001616 final int minorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001618 switch (majorGravity) {
1619 case Gravity.BOTTOM:
1620 // mTotalLength contains the padding already
Philip Milnead365cc2012-09-27 14:38:46 -07001621 childTop = mPaddingTop + bottom - top - mTotalLength;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001622 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001623
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001624 // mTotalLength contains the padding already
1625 case Gravity.CENTER_VERTICAL:
Philip Milnead365cc2012-09-27 14:38:46 -07001626 childTop = mPaddingTop + (bottom - top - mTotalLength) / 2;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001627 break;
1628
1629 case Gravity.TOP:
1630 default:
1631 childTop = mPaddingTop;
1632 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001633 }
Adam Powellfcca00a2010-11-30 21:26:29 -08001634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001635 for (int i = 0; i < count; i++) {
1636 final View child = getVirtualChildAt(i);
1637 if (child == null) {
1638 childTop += measureNullChild(i);
1639 } else if (child.getVisibility() != GONE) {
1640 final int childWidth = child.getMeasuredWidth();
1641 final int childHeight = child.getMeasuredHeight();
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001642
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001643 final LinearLayout.LayoutParams lp =
1644 (LinearLayout.LayoutParams) child.getLayoutParams();
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001645
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001646 int gravity = lp.gravity;
1647 if (gravity < 0) {
1648 gravity = minorGravity;
1649 }
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07001650 final int layoutDirection = getLayoutDirection();
Fabrice Di Meglioc0053222011-06-13 12:16:51 -07001651 final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
Fabrice Di Megliode35cee2011-06-01 15:13:50 -07001652 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001653 case Gravity.CENTER_HORIZONTAL:
1654 childLeft = paddingLeft + ((childSpace - childWidth) / 2)
1655 + lp.leftMargin - lp.rightMargin;
1656 break;
1657
1658 case Gravity.RIGHT:
1659 childLeft = childRight - childWidth - lp.rightMargin;
1660 break;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001661
1662 case Gravity.LEFT:
Romain Guy611cd3f2009-12-15 12:00:37 -08001663 default:
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001664 childLeft = paddingLeft + lp.leftMargin;
Romain Guy611cd3f2009-12-15 12:00:37 -08001665 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001666 }
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001667
Adam Powell696cba52011-03-29 10:38:16 -07001668 if (hasDividerBeforeChildAt(i)) {
1669 childTop += mDividerHeight;
1670 }
1671
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001672 childTop += lp.topMargin;
1673 setChildFrame(child, childLeft, childTop + getLocationOffset(child),
1674 childWidth, childHeight);
1675 childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);
1676
1677 i += getChildrenSkipCount(child, i);
1678 }
1679 }
1680 }
1681
Selim Cinek78528b22015-06-02 17:33:09 +02001682 @Override
1683 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) {
1684 super.onRtlPropertiesChanged(layoutDirection);
1685 if (layoutDirection != mLayoutDirection) {
1686 mLayoutDirection = layoutDirection;
1687 if (mOrientation == HORIZONTAL) {
1688 requestLayout();
1689 }
1690 }
1691 }
1692
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001693 /**
1694 * Position the children during a layout pass if the orientation of this
1695 * LinearLayout is set to {@link #HORIZONTAL}.
1696 *
1697 * @see #getOrientation()
1698 * @see #setOrientation(int)
1699 * @see #onLayout(boolean, int, int, int, int)
Philip Milnead365cc2012-09-27 14:38:46 -07001700 * @param left
1701 * @param top
1702 * @param right
1703 * @param bottom
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001704 */
Philip Milnead365cc2012-09-27 14:38:46 -07001705 void layoutHorizontal(int left, int top, int right, int bottom) {
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001706 final boolean isLayoutRtl = isLayoutRtl();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707 final int paddingTop = mPaddingTop;
1708
Romain Guy5b1b2412010-01-21 19:09:51 -08001709 int childTop;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001710 int childLeft;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001711
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001712 // Where bottom of child should go
Philip Milnead365cc2012-09-27 14:38:46 -07001713 final int height = bottom - top;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001714 int childBottom = height - mPaddingBottom;
1715
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001716 // Space available for child
1717 int childSpace = height - paddingTop - mPaddingBottom;
1718
1719 final int count = getVirtualChildCount();
1720
Fabrice Di Meglio6a036402011-05-23 14:43:23 -07001721 final int majorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001722 final int minorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
1723
1724 final boolean baselineAligned = mBaselineAligned;
1725
1726 final int[] maxAscent = mMaxAscent;
1727 final int[] maxDescent = mMaxDescent;
1728
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07001729 final int layoutDirection = getLayoutDirection();
Fabrice Di Meglioc0053222011-06-13 12:16:51 -07001730 switch (Gravity.getAbsoluteGravity(majorGravity, layoutDirection)) {
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001731 case Gravity.RIGHT:
1732 // mTotalLength contains the padding already
Philip Milnead365cc2012-09-27 14:38:46 -07001733 childLeft = mPaddingLeft + right - left - mTotalLength;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001734 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001735
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001736 case Gravity.CENTER_HORIZONTAL:
1737 // mTotalLength contains the padding already
Philip Milnead365cc2012-09-27 14:38:46 -07001738 childLeft = mPaddingLeft + (right - left - mTotalLength) / 2;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001739 break;
1740
1741 case Gravity.LEFT:
1742 default:
1743 childLeft = mPaddingLeft;
1744 break;
1745 }
1746
1747 int start = 0;
1748 int dir = 1;
1749 //In case of RTL, start drawing from the last child.
1750 if (isLayoutRtl) {
1751 start = count - 1;
1752 dir = -1;
Adam Powellfcca00a2010-11-30 21:26:29 -08001753 }
1754
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 for (int i = 0; i < count; i++) {
Alan Viverettead526932015-12-17 12:42:39 -05001756 final int childIndex = start + dir * i;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001757 final View child = getVirtualChildAt(childIndex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001758 if (child == null) {
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001759 childLeft += measureNullChild(childIndex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001760 } else if (child.getVisibility() != GONE) {
1761 final int childWidth = child.getMeasuredWidth();
1762 final int childHeight = child.getMeasuredHeight();
1763 int childBaseline = -1;
1764
1765 final LinearLayout.LayoutParams lp =
1766 (LinearLayout.LayoutParams) child.getLayoutParams();
1767
Romain Guy980a9382010-01-08 15:06:28 -08001768 if (baselineAligned && lp.height != LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001769 childBaseline = child.getBaseline();
1770 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001771
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001772 int gravity = lp.gravity;
1773 if (gravity < 0) {
1774 gravity = minorGravity;
1775 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001776
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001777 switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
1778 case Gravity.TOP:
1779 childTop = paddingTop + lp.topMargin;
1780 if (childBaseline != -1) {
1781 childTop += maxAscent[INDEX_TOP] - childBaseline;
1782 }
1783 break;
1784
1785 case Gravity.CENTER_VERTICAL:
Romain Guy5b1b2412010-01-21 19:09:51 -08001786 // Removed support for baseline alignment when layout_gravity or
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001787 // gravity == center_vertical. See bug #1038483.
1788 // Keep the code around if we need to re-enable this feature
1789 // if (childBaseline != -1) {
1790 // // Align baselines vertically only if the child is smaller than us
1791 // if (childSpace - childHeight > 0) {
1792 // childTop = paddingTop + (childSpace / 2) - childBaseline;
1793 // } else {
1794 // childTop = paddingTop + (childSpace - childHeight) / 2;
1795 // }
1796 // } else {
1797 childTop = paddingTop + ((childSpace - childHeight) / 2)
1798 + lp.topMargin - lp.bottomMargin;
1799 break;
1800
1801 case Gravity.BOTTOM:
1802 childTop = childBottom - childHeight - lp.bottomMargin;
1803 if (childBaseline != -1) {
1804 int descent = child.getMeasuredHeight() - childBaseline;
1805 childTop -= (maxDescent[INDEX_BOTTOM] - descent);
1806 }
1807 break;
Romain Guy611cd3f2009-12-15 12:00:37 -08001808 default:
1809 childTop = paddingTop;
1810 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001811 }
1812
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001813 if (hasDividerBeforeChildAt(childIndex)) {
Adam Powell696cba52011-03-29 10:38:16 -07001814 childLeft += mDividerWidth;
1815 }
1816
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001817 childLeft += lp.leftMargin;
1818 setChildFrame(child, childLeft + getLocationOffset(child), childTop,
1819 childWidth, childHeight);
1820 childLeft += childWidth + lp.rightMargin +
1821 getNextLocationOffset(child);
1822
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001823 i += getChildrenSkipCount(child, childIndex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001824 }
1825 }
1826 }
1827
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001828 private void setChildFrame(View child, int left, int top, int width, int height) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001829 child.layout(left, top, left + width, top + height);
1830 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001831
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001832 /**
1833 * Should the layout be a column or a row.
Tor Norbyed9273d62013-05-30 15:59:53 -07001834 * @param orientation Pass {@link #HORIZONTAL} or {@link #VERTICAL}. Default
1835 * value is {@link #HORIZONTAL}.
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001836 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001837 * @attr ref android.R.styleable#LinearLayout_orientation
1838 */
Tor Norbyed9273d62013-05-30 15:59:53 -07001839 public void setOrientation(@OrientationMode int orientation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001840 if (mOrientation != orientation) {
1841 mOrientation = orientation;
1842 requestLayout();
1843 }
1844 }
1845
1846 /**
1847 * Returns the current orientation.
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001848 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001849 * @return either {@link #HORIZONTAL} or {@link #VERTICAL}
1850 */
Tor Norbyed9273d62013-05-30 15:59:53 -07001851 @OrientationMode
Ashley Rose55f9f922019-01-28 19:29:36 -05001852 @InspectableProperty(enumMapping = {
1853 @InspectableProperty.EnumMap(value = HORIZONTAL, name = "horizontal"),
1854 @InspectableProperty.EnumMap(value = VERTICAL, name = "vertical")
1855 })
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001856 public int getOrientation() {
1857 return mOrientation;
1858 }
1859
1860 /**
1861 * Describes how the child views are positioned. Defaults to GRAVITY_TOP. If
1862 * this layout has a VERTICAL orientation, this controls where all the child
1863 * views are placed if there is extra vertical space. If this layout has a
1864 * HORIZONTAL orientation, this controls the alignment of the children.
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001865 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001866 * @param gravity See {@link android.view.Gravity}
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001867 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001868 * @attr ref android.R.styleable#LinearLayout_gravity
1869 */
1870 @android.view.RemotableViewMethod
1871 public void setGravity(int gravity) {
1872 if (mGravity != gravity) {
Fabrice Di Meglio6a036402011-05-23 14:43:23 -07001873 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
Fabrice Di Meglio9e3b0022011-06-06 16:30:29 -07001874 gravity |= Gravity.START;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001875 }
1876
1877 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
1878 gravity |= Gravity.TOP;
1879 }
1880
1881 mGravity = gravity;
1882 requestLayout();
1883 }
1884 }
1885
Jason Monkefe916c2016-01-20 10:46:12 -05001886 /**
1887 * Returns the current gravity. See {@link android.view.Gravity}
1888 *
1889 * @return the current gravity.
1890 * @see #setGravity
1891 */
Ashley Rose55f9f922019-01-28 19:29:36 -05001892 @InspectableProperty(valueType = InspectableProperty.ValueType.GRAVITY)
Jason Monkefe916c2016-01-20 10:46:12 -05001893 public int getGravity() {
1894 return mGravity;
1895 }
1896
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001897 @android.view.RemotableViewMethod
1898 public void setHorizontalGravity(int horizontalGravity) {
Fabrice Di Meglio6a036402011-05-23 14:43:23 -07001899 final int gravity = horizontalGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
1900 if ((mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) != gravity) {
1901 mGravity = (mGravity & ~Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) | gravity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001902 requestLayout();
1903 }
1904 }
1905
1906 @android.view.RemotableViewMethod
1907 public void setVerticalGravity(int verticalGravity) {
1908 final int gravity = verticalGravity & Gravity.VERTICAL_GRAVITY_MASK;
1909 if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != gravity) {
1910 mGravity = (mGravity & ~Gravity.VERTICAL_GRAVITY_MASK) | gravity;
1911 requestLayout();
1912 }
1913 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001914
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001915 @Override
1916 public LayoutParams generateLayoutParams(AttributeSet attrs) {
1917 return new LinearLayout.LayoutParams(getContext(), attrs);
1918 }
1919
1920 /**
1921 * Returns a set of layout parameters with a width of
Romain Guy980a9382010-01-08 15:06:28 -08001922 * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001923 * and a height of {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}
1924 * when the layout's orientation is {@link #VERTICAL}. When the orientation is
1925 * {@link #HORIZONTAL}, the width is set to {@link LayoutParams#WRAP_CONTENT}
1926 * and the height to {@link LayoutParams#WRAP_CONTENT}.
1927 */
1928 @Override
1929 protected LayoutParams generateDefaultLayoutParams() {
1930 if (mOrientation == HORIZONTAL) {
1931 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
1932 } else if (mOrientation == VERTICAL) {
Romain Guy980a9382010-01-08 15:06:28 -08001933 return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001934 }
1935 return null;
1936 }
1937
1938 @Override
Yigit Boyar885c50b2016-03-22 16:53:42 -07001939 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
Yigit Boyar2dd20a62016-08-01 17:42:28 -07001940 if (sPreserveMarginParamsInLayoutParamConversion) {
1941 if (lp instanceof LayoutParams) {
1942 return new LayoutParams((LayoutParams) lp);
1943 } else if (lp instanceof MarginLayoutParams) {
1944 return new LayoutParams((MarginLayoutParams) lp);
1945 }
Yigit Boyar885c50b2016-03-22 16:53:42 -07001946 }
Yigit Boyar2dd20a62016-08-01 17:42:28 -07001947 return new LayoutParams(lp);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001948 }
1949
1950
1951 // Override to allow type-checking of LayoutParams.
1952 @Override
1953 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
1954 return p instanceof LinearLayout.LayoutParams;
1955 }
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08001956
1957 @Override
Dianne Hackborna7bb6fb2015-02-03 18:13:40 -08001958 public CharSequence getAccessibilityClassName() {
1959 return LinearLayout.class.getName();
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08001960 }
1961
Siva Velusamy94a6d152015-05-05 15:07:00 -07001962 /** @hide */
1963 @Override
1964 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
1965 super.encodeProperties(encoder);
1966 encoder.addProperty("layout:baselineAligned", mBaselineAligned);
1967 encoder.addProperty("layout:baselineAlignedChildIndex", mBaselineAlignedChildIndex);
1968 encoder.addProperty("measurement:baselineChildTop", mBaselineChildTop);
1969 encoder.addProperty("measurement:orientation", mOrientation);
1970 encoder.addProperty("measurement:gravity", mGravity);
1971 encoder.addProperty("measurement:totalLength", mTotalLength);
1972 encoder.addProperty("layout:totalLength", mTotalLength);
1973 encoder.addProperty("layout:useLargestChild", mUseLargestChild);
1974 }
1975
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001976 /**
1977 * Per-child layout information associated with ViewLinearLayout.
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001978 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001979 * @attr ref android.R.styleable#LinearLayout_Layout_layout_weight
1980 * @attr ref android.R.styleable#LinearLayout_Layout_layout_gravity
1981 */
1982 public static class LayoutParams extends ViewGroup.MarginLayoutParams {
1983 /**
1984 * Indicates how much of the extra space in the LinearLayout will be
1985 * allocated to the view associated with these LayoutParams. Specify
1986 * 0 if the view should not be stretched. Otherwise the extra pixels
1987 * will be pro-rated among all views whose weight is greater than 0.
1988 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07001989 @ViewDebug.ExportedProperty(category = "layout")
Ashley Rosede3b4a72019-03-04 16:44:07 -05001990 @InspectableProperty(name = "layout_weight")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001991 public float weight;
1992
1993 /**
1994 * Gravity for the view associated with these LayoutParams.
1995 *
1996 * @see android.view.Gravity
1997 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07001998 @ViewDebug.ExportedProperty(category = "layout", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001999 @ViewDebug.IntToString(from = -1, to = "NONE"),
2000 @ViewDebug.IntToString(from = Gravity.NO_GRAVITY, to = "NONE"),
2001 @ViewDebug.IntToString(from = Gravity.TOP, to = "TOP"),
2002 @ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"),
2003 @ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"),
2004 @ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"),
Chet Haase8b9ed442016-08-25 15:35:53 -07002005 @ViewDebug.IntToString(from = Gravity.START, to = "START"),
2006 @ViewDebug.IntToString(from = Gravity.END, to = "END"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002007 @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"),
2008 @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"),
2009 @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
2010 @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL, to = "FILL_HORIZONTAL"),
2011 @ViewDebug.IntToString(from = Gravity.CENTER, to = "CENTER"),
2012 @ViewDebug.IntToString(from = Gravity.FILL, to = "FILL")
2013 })
Ashley Rosede3b4a72019-03-04 16:44:07 -05002014 @InspectableProperty(
2015 name = "layout_gravity",
2016 valueType = InspectableProperty.ValueType.GRAVITY)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002017 public int gravity = -1;
2018
2019 /**
2020 * {@inheritDoc}
2021 */
2022 public LayoutParams(Context c, AttributeSet attrs) {
2023 super(c, attrs);
2024 TypedArray a =
2025 c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout_Layout);
2026
2027 weight = a.getFloat(com.android.internal.R.styleable.LinearLayout_Layout_layout_weight, 0);
2028 gravity = a.getInt(com.android.internal.R.styleable.LinearLayout_Layout_layout_gravity, -1);
2029
2030 a.recycle();
2031 }
2032
2033 /**
2034 * {@inheritDoc}
2035 */
2036 public LayoutParams(int width, int height) {
2037 super(width, height);
2038 weight = 0;
2039 }
2040
2041 /**
2042 * Creates a new set of layout parameters with the specified width, height
2043 * and weight.
2044 *
Romain Guy980a9382010-01-08 15:06:28 -08002045 * @param width the width, either {@link #MATCH_PARENT},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002046 * {@link #WRAP_CONTENT} or a fixed size in pixels
Romain Guy980a9382010-01-08 15:06:28 -08002047 * @param height the height, either {@link #MATCH_PARENT},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002048 * {@link #WRAP_CONTENT} or a fixed size in pixels
2049 * @param weight the weight
2050 */
2051 public LayoutParams(int width, int height, float weight) {
2052 super(width, height);
2053 this.weight = weight;
2054 }
2055
2056 /**
2057 * {@inheritDoc}
2058 */
2059 public LayoutParams(ViewGroup.LayoutParams p) {
2060 super(p);
2061 }
2062
2063 /**
2064 * {@inheritDoc}
2065 */
Alan Viverette0a0e1552013-08-07 13:24:09 -07002066 public LayoutParams(ViewGroup.MarginLayoutParams source) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002067 super(source);
2068 }
2069
Alan Viverette0a0e1552013-08-07 13:24:09 -07002070 /**
2071 * Copy constructor. Clones the width, height, margin values, weight,
2072 * and gravity of the source.
2073 *
2074 * @param source The layout params to copy from.
2075 */
2076 public LayoutParams(LayoutParams source) {
2077 super(source);
2078
2079 this.weight = source.weight;
2080 this.gravity = source.gravity;
2081 }
2082
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002083 @Override
2084 public String debug(String output) {
2085 return output + "LinearLayout.LayoutParams={width=" + sizeToString(width) +
2086 ", height=" + sizeToString(height) + " weight=" + weight + "}";
2087 }
Siva Velusamy94a6d152015-05-05 15:07:00 -07002088
2089 /** @hide */
2090 @Override
Mathew Inwooda85f4eb2018-08-21 16:08:34 +01002091 @UnsupportedAppUsage
Siva Velusamy94a6d152015-05-05 15:07:00 -07002092 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
2093 super.encodeProperties(encoder);
2094
2095 encoder.addProperty("layout:weight", weight);
2096 encoder.addProperty("layout:gravity", gravity);
2097 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002098 }
2099}