blob: ff3c85c99f539e7e88192fe1ad6ee0473413e754 [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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.content.Context;
23import android.content.res.TypedArray;
Adam Powellfcca00a2010-11-30 21:26:29 -080024import android.graphics.Canvas;
25import android.graphics.drawable.Drawable;
Alan Viverette40e1df32015-08-25 16:50:27 -040026import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.util.AttributeSet;
28import android.view.Gravity;
29import android.view.View;
30import android.view.ViewDebug;
31import android.view.ViewGroup;
Siva Velusamy94a6d152015-05-05 15:07:00 -070032import android.view.ViewHierarchyEncoder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.widget.RemoteViews.RemoteView;
34
Aurimas Liutikas99441c52016-10-11 16:48:32 -070035import com.android.internal.R;
36
Tor Norbyed9273d62013-05-30 15:59:53 -070037import java.lang.annotation.Retention;
38import java.lang.annotation.RetentionPolicy;
39
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040
41/**
Joe Fernandezd9ffaa52017-04-25 23:39:17 -070042 * A layout that arranges other views either horizontally in a single column
43 * or vertically in a single row.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044 *
Joe Fernandezd9ffaa52017-04-25 23:39:17 -070045 * <p>The following snippet shows how to include a linear layout in your layout XML file:</p>
Scott Main41ec6532010-08-19 16:57:07 -070046 *
Joe Fernandezd9ffaa52017-04-25 23:39:17 -070047 * <pre>&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
48 * android:layout_width="match_parent"
49 * android:layout_height="match_parent"
50 * android:paddingLeft="16dp"
51 * android:paddingRight="16dp"
52 * android:orientation="horizontal"
53 * android:gravity="center"&gt;
54 *
55 * &lt;!-- Include other widget or layout tags here. These are considered
56 * "child views" or "children" of the linear layout --&gt;
57 *
58 * &lt;/LinearLayout&gt;</pre>
59 *
60 * <p>Set {@link android.R.styleable#LinearLayout_orientation android:orientation} to specify
61 * whether child views are displayed in a row or column.</p>
62 *
63 * <p>To control how linear layout aligns all the views it contains, set a value for
64 * {@link android.R.styleable#LinearLayout_gravity android:gravity}. For example, the
65 * snippet above sets android:gravity to "center". The value you set affects
66 * both horizontal and vertical alignment of all child views within the single row or column.</p>
67 *
68 * <p>You can set
69 * {@link LinearLayout.LayoutParams.html#attr_android:layout_weight android:layout_weight}
70 * on individual child views to specify how linear layout divides remaining space amongst
71 * the views it contains. See the
72 * <a href="https://developer.android.com/guide/topics/ui/layout/linear.html">Linear Layout</a>
73 * guide for an example.</p>
74 *
75 * <p>See
76 * {@link android.widget.LinearLayout.LayoutParams LinearLayout.LayoutParams}
77 * to learn about other attributes you can set on a child view to affect its
78 * position and size in the containing linear layout.</p>
Romain Guy9295ada2010-06-15 11:33:24 -070079 *
80 * @attr ref android.R.styleable#LinearLayout_baselineAligned
81 * @attr ref android.R.styleable#LinearLayout_baselineAlignedChildIndex
82 * @attr ref android.R.styleable#LinearLayout_gravity
83 * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
84 * @attr ref android.R.styleable#LinearLayout_orientation
85 * @attr ref android.R.styleable#LinearLayout_weightSum
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 */
87@RemoteView
88public class LinearLayout extends ViewGroup {
Tor Norbyed9273d62013-05-30 15:59:53 -070089 /** @hide */
90 @IntDef({HORIZONTAL, VERTICAL})
91 @Retention(RetentionPolicy.SOURCE)
92 public @interface OrientationMode {}
93
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 public static final int HORIZONTAL = 0;
95 public static final int VERTICAL = 1;
96
Tor Norbyed9273d62013-05-30 15:59:53 -070097 /** @hide */
98 @IntDef(flag = true,
99 value = {
100 SHOW_DIVIDER_NONE,
101 SHOW_DIVIDER_BEGINNING,
102 SHOW_DIVIDER_MIDDLE,
103 SHOW_DIVIDER_END
104 })
105 @Retention(RetentionPolicy.SOURCE)
106 public @interface DividerMode {}
107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 /**
Adam Powellfcca00a2010-11-30 21:26:29 -0800109 * Don't show any dividers.
110 */
111 public static final int SHOW_DIVIDER_NONE = 0;
112 /**
113 * Show a divider at the beginning of the group.
114 */
115 public static final int SHOW_DIVIDER_BEGINNING = 1;
116 /**
117 * Show dividers between each item in the group.
118 */
119 public static final int SHOW_DIVIDER_MIDDLE = 2;
120 /**
121 * Show a divider at the end of the group.
122 */
123 public static final int SHOW_DIVIDER_END = 4;
124
125 /**
Alan Viverette40e1df32015-08-25 16:50:27 -0400126 * Compatibility check. Old versions of the platform would give different
127 * results from measurement passes using EXACTLY and non-EXACTLY modes,
128 * even when the resulting size was the same.
129 */
130 private final boolean mAllowInconsistentMeasurement;
131
132 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 * Whether the children of this layout are baseline aligned. Only applicable
134 * if {@link #mOrientation} is horizontal.
135 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700136 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 private boolean mBaselineAligned = true;
138
139 /**
140 * If this layout is part of another layout that is baseline aligned,
141 * use the child at this index as the baseline.
142 *
143 * Note: this is orthogonal to {@link #mBaselineAligned}, which is concerned
144 * with whether the children of this layout are baseline aligned.
145 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700146 @ViewDebug.ExportedProperty(category = "layout")
Karl Rosaenc1f9c402009-08-12 17:18:33 -0700147 private int mBaselineAlignedChildIndex = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148
149 /**
150 * The additional offset to the child's baseline.
151 * We'll calculate the baseline of this layout as we measure vertically; for
152 * horizontal linear layouts, the offset of 0 is appropriate.
153 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700154 @ViewDebug.ExportedProperty(category = "measurement")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 private int mBaselineChildTop = 0;
156
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700157 @ViewDebug.ExportedProperty(category = "measurement")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 private int mOrientation;
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700159
Fabrice Di Megliobce84d22011-06-02 15:57:01 -0700160 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = {
161 @ViewDebug.FlagToString(mask = -1,
162 equals = -1, name = "NONE"),
163 @ViewDebug.FlagToString(mask = Gravity.NO_GRAVITY,
164 equals = Gravity.NO_GRAVITY,name = "NONE"),
165 @ViewDebug.FlagToString(mask = Gravity.TOP,
166 equals = Gravity.TOP, name = "TOP"),
167 @ViewDebug.FlagToString(mask = Gravity.BOTTOM,
168 equals = Gravity.BOTTOM, name = "BOTTOM"),
169 @ViewDebug.FlagToString(mask = Gravity.LEFT,
170 equals = Gravity.LEFT, name = "LEFT"),
171 @ViewDebug.FlagToString(mask = Gravity.RIGHT,
172 equals = Gravity.RIGHT, name = "RIGHT"),
Fabrice Di Meglio9e3b0022011-06-06 16:30:29 -0700173 @ViewDebug.FlagToString(mask = Gravity.START,
174 equals = Gravity.START, name = "START"),
175 @ViewDebug.FlagToString(mask = Gravity.END,
176 equals = Gravity.END, name = "END"),
Fabrice Di Megliobce84d22011-06-02 15:57:01 -0700177 @ViewDebug.FlagToString(mask = Gravity.CENTER_VERTICAL,
178 equals = Gravity.CENTER_VERTICAL, name = "CENTER_VERTICAL"),
179 @ViewDebug.FlagToString(mask = Gravity.FILL_VERTICAL,
180 equals = Gravity.FILL_VERTICAL, name = "FILL_VERTICAL"),
181 @ViewDebug.FlagToString(mask = Gravity.CENTER_HORIZONTAL,
182 equals = Gravity.CENTER_HORIZONTAL, name = "CENTER_HORIZONTAL"),
183 @ViewDebug.FlagToString(mask = Gravity.FILL_HORIZONTAL,
184 equals = Gravity.FILL_HORIZONTAL, name = "FILL_HORIZONTAL"),
185 @ViewDebug.FlagToString(mask = Gravity.CENTER,
186 equals = Gravity.CENTER, name = "CENTER"),
187 @ViewDebug.FlagToString(mask = Gravity.FILL,
188 equals = Gravity.FILL, name = "FILL"),
Fabrice Di Meglioc46f7ff2011-06-06 18:23:10 -0700189 @ViewDebug.FlagToString(mask = Gravity.RELATIVE_LAYOUT_DIRECTION,
190 equals = Gravity.RELATIVE_LAYOUT_DIRECTION, name = "RELATIVE")
Jon Miranda4597e982014-07-29 07:25:49 -0700191 }, formatToHexString = true)
Fabrice Di Meglio9e3b0022011-06-06 16:30:29 -0700192 private int mGravity = Gravity.START | Gravity.TOP;
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700193
194 @ViewDebug.ExportedProperty(category = "measurement")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 private int mTotalLength;
196
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700197 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 private float mWeightSum;
199
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700200 @ViewDebug.ExportedProperty(category = "layout")
Romain Guy5b1b2412010-01-21 19:09:51 -0800201 private boolean mUseLargestChild;
202
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 private int[] mMaxAscent;
204 private int[] mMaxDescent;
205
206 private static final int VERTICAL_GRAVITY_COUNT = 4;
207
208 private static final int INDEX_CENTER_VERTICAL = 0;
209 private static final int INDEX_TOP = 1;
210 private static final int INDEX_BOTTOM = 2;
Romain Guy5b1b2412010-01-21 19:09:51 -0800211 private static final int INDEX_FILL = 3;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212
Adam Powellfcca00a2010-11-30 21:26:29 -0800213 private Drawable mDivider;
214 private int mDividerWidth;
215 private int mDividerHeight;
216 private int mShowDividers;
217 private int mDividerPadding;
218
Selim Cinek78528b22015-06-02 17:33:09 +0200219 private int mLayoutDirection = View.LAYOUT_DIRECTION_UNDEFINED;
220
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221 public LinearLayout(Context context) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700222 this(context, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 }
224
Scott Kennedy3a1fa102015-03-05 19:15:11 -0800225 public LinearLayout(Context context, @Nullable AttributeSet attrs) {
Romain Guy9295ada2010-06-15 11:33:24 -0700226 this(context, attrs, 0);
227 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700228
Scott Kennedy3a1fa102015-03-05 19:15:11 -0800229 public LinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
Alan Viverette617feb92013-09-09 18:09:13 -0700230 this(context, attrs, defStyleAttr, 0);
231 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232
Alan Viverette617feb92013-09-09 18:09:13 -0700233 public LinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
234 super(context, attrs, defStyleAttr, defStyleRes);
235
236 final TypedArray a = context.obtainStyledAttributes(
237 attrs, com.android.internal.R.styleable.LinearLayout, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238
239 int index = a.getInt(com.android.internal.R.styleable.LinearLayout_orientation, -1);
240 if (index >= 0) {
241 setOrientation(index);
242 }
243
244 index = a.getInt(com.android.internal.R.styleable.LinearLayout_gravity, -1);
245 if (index >= 0) {
246 setGravity(index);
247 }
248
249 boolean baselineAligned = a.getBoolean(R.styleable.LinearLayout_baselineAligned, true);
250 if (!baselineAligned) {
251 setBaselineAligned(baselineAligned);
252 }
253
254 mWeightSum = a.getFloat(R.styleable.LinearLayout_weightSum, -1.0f);
255
256 mBaselineAlignedChildIndex =
257 a.getInt(com.android.internal.R.styleable.LinearLayout_baselineAlignedChildIndex, -1);
258
Romain Guy9295ada2010-06-15 11:33:24 -0700259 mUseLargestChild = a.getBoolean(R.styleable.LinearLayout_measureWithLargestChild, false);
Romain Guy5b1b2412010-01-21 19:09:51 -0800260
Adam Powellfcca00a2010-11-30 21:26:29 -0800261 setDividerDrawable(a.getDrawable(R.styleable.LinearLayout_divider));
262 mShowDividers = a.getInt(R.styleable.LinearLayout_showDividers, SHOW_DIVIDER_NONE);
263 mDividerPadding = a.getDimensionPixelSize(R.styleable.LinearLayout_dividerPadding, 0);
264
Alan Viverette40e1df32015-08-25 16:50:27 -0400265 final int version = context.getApplicationInfo().targetSdkVersion;
266 mAllowInconsistentMeasurement = version <= Build.VERSION_CODES.M;
267
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 a.recycle();
269 }
270
271 /**
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400272 * Returns <code>true</code> if this layout is currently configured to show at least one
273 * divider.
274 */
275 private boolean isShowingDividers() {
276 return (mShowDividers != SHOW_DIVIDER_NONE) && (mDivider != null);
277 }
278
279 /**
Adam Powellfcca00a2010-11-30 21:26:29 -0800280 * Set how dividers should be shown between items in this layout
281 *
282 * @param showDividers One or more of {@link #SHOW_DIVIDER_BEGINNING},
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400283 * {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END}
284 * to show dividers, or {@link #SHOW_DIVIDER_NONE} to show no dividers.
Adam Powellfcca00a2010-11-30 21:26:29 -0800285 */
Tor Norbyed9273d62013-05-30 15:59:53 -0700286 public void setShowDividers(@DividerMode int showDividers) {
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400287 if (showDividers == mShowDividers) {
288 return;
Adam Powellfcca00a2010-11-30 21:26:29 -0800289 }
290 mShowDividers = showDividers;
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400291
292 setWillNotDraw(!isShowingDividers());
293 requestLayout();
Adam Powellfcca00a2010-11-30 21:26:29 -0800294 }
295
Patrick Dubroye0a799a2011-05-04 16:19:22 -0700296 @Override
297 public boolean shouldDelayChildPressedState() {
298 return false;
299 }
300
Adam Powellfcca00a2010-11-30 21:26:29 -0800301 /**
302 * @return A flag set indicating how dividers should be shown around items.
303 * @see #setShowDividers(int)
304 */
Tor Norbyed9273d62013-05-30 15:59:53 -0700305 @DividerMode
Adam Powellfcca00a2010-11-30 21:26:29 -0800306 public int getShowDividers() {
307 return mShowDividers;
308 }
309
310 /**
Philip Milne1018fb42012-03-13 12:00:04 -0700311 * @return the divider Drawable that will divide each item.
312 *
313 * @see #setDividerDrawable(Drawable)
314 *
315 * @attr ref android.R.styleable#LinearLayout_divider
316 */
317 public Drawable getDividerDrawable() {
318 return mDivider;
319 }
320
321 /**
Adam Powellfcca00a2010-11-30 21:26:29 -0800322 * Set a drawable to be used as a divider between items.
Philip Milne1018fb42012-03-13 12:00:04 -0700323 *
Adam Powellfcca00a2010-11-30 21:26:29 -0800324 * @param divider Drawable that will divide each item.
Philip Milne1018fb42012-03-13 12:00:04 -0700325 *
Adam Powellfcca00a2010-11-30 21:26:29 -0800326 * @see #setShowDividers(int)
Philip Milne1018fb42012-03-13 12:00:04 -0700327 *
328 * @attr ref android.R.styleable#LinearLayout_divider
Adam Powellfcca00a2010-11-30 21:26:29 -0800329 */
330 public void setDividerDrawable(Drawable divider) {
331 if (divider == mDivider) {
332 return;
333 }
334 mDivider = divider;
335 if (divider != null) {
336 mDividerWidth = divider.getIntrinsicWidth();
337 mDividerHeight = divider.getIntrinsicHeight();
338 } else {
339 mDividerWidth = 0;
340 mDividerHeight = 0;
341 }
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400342
343 setWillNotDraw(!isShowingDividers());
Adam Powellfcca00a2010-11-30 21:26:29 -0800344 requestLayout();
345 }
346
Adam Powell696cba52011-03-29 10:38:16 -0700347 /**
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400348 * Set padding displayed on both ends of dividers. For a vertical layout, the padding is applied
349 * to left and right end of dividers. For a horizontal layout, the padding is applied to top and
350 * bottom end of dividers.
Adam Powell696cba52011-03-29 10:38:16 -0700351 *
352 * @param padding Padding value in pixels that will be applied to each end
353 *
354 * @see #setShowDividers(int)
355 * @see #setDividerDrawable(Drawable)
356 * @see #getDividerPadding()
357 */
358 public void setDividerPadding(int padding) {
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400359 if (padding == mDividerPadding) {
360 return;
361 }
Adam Powell696cba52011-03-29 10:38:16 -0700362 mDividerPadding = padding;
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400363
364 if (isShowingDividers()) {
365 requestLayout();
366 invalidate();
367 }
Adam Powell696cba52011-03-29 10:38:16 -0700368 }
369
370 /**
371 * Get the padding size used to inset dividers in pixels
372 *
373 * @see #setShowDividers(int)
374 * @see #setDividerDrawable(Drawable)
375 * @see #setDividerPadding(int)
376 */
377 public int getDividerPadding() {
378 return mDividerPadding;
379 }
380
Adam Powell640a66e2011-04-29 10:18:53 -0700381 /**
382 * Get the width of the current divider drawable.
383 *
384 * @hide Used internally by framework.
385 */
386 public int getDividerWidth() {
387 return mDividerWidth;
388 }
389
Adam Powellfcca00a2010-11-30 21:26:29 -0800390 @Override
391 protected void onDraw(Canvas canvas) {
392 if (mDivider == null) {
393 return;
394 }
395
396 if (mOrientation == VERTICAL) {
397 drawDividersVertical(canvas);
398 } else {
399 drawDividersHorizontal(canvas);
400 }
401 }
402
403 void drawDividersVertical(Canvas canvas) {
Adam Powellfcca00a2010-11-30 21:26:29 -0800404 final int count = getVirtualChildCount();
Adam Powellfcca00a2010-11-30 21:26:29 -0800405 for (int i = 0; i < count; i++) {
406 final View child = getVirtualChildAt(i);
Adam Powell35aecd52011-07-01 13:43:49 -0700407 if (child != null && child.getVisibility() != GONE) {
Adam Powell696cba52011-03-29 10:38:16 -0700408 if (hasDividerBeforeChildAt(i)) {
Adam Powell35aecd52011-07-01 13:43:49 -0700409 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Vladimir Baryshnikov20761fc2012-01-17 14:59:48 -0800410 final int top = child.getTop() - lp.topMargin - mDividerHeight;
Adam Powellfcca00a2010-11-30 21:26:29 -0800411 drawHorizontalDivider(canvas, top);
Adam Powellfcca00a2010-11-30 21:26:29 -0800412 }
Adam Powellfcca00a2010-11-30 21:26:29 -0800413 }
414 }
415
Adam Powell696cba52011-03-29 10:38:16 -0700416 if (hasDividerBeforeChildAt(count)) {
Doris Liuec6a4cd2015-06-25 15:16:54 -0700417 final View child = getLastNonGoneChild();
Adam Powell35aecd52011-07-01 13:43:49 -0700418 int bottom = 0;
419 if (child == null) {
420 bottom = getHeight() - getPaddingBottom() - mDividerHeight;
421 } else {
422 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
423 bottom = child.getBottom() + lp.bottomMargin;
424 }
425 drawHorizontalDivider(canvas, bottom);
Adam Powellfcca00a2010-11-30 21:26:29 -0800426 }
427 }
428
Doris Liuec6a4cd2015-06-25 15:16:54 -0700429 /**
430 * Finds the last child that is not gone. The last child will be used as the reference for
431 * where the end divider should be drawn.
432 */
433 private View getLastNonGoneChild() {
434 for (int i = getVirtualChildCount() - 1; i >= 0; i--) {
Alan Viverettead526932015-12-17 12:42:39 -0500435 final View child = getVirtualChildAt(i);
Doris Liuec6a4cd2015-06-25 15:16:54 -0700436 if (child != null && child.getVisibility() != GONE) {
437 return child;
438 }
439 }
440 return null;
441 }
442
Adam Powellfcca00a2010-11-30 21:26:29 -0800443 void drawDividersHorizontal(Canvas canvas) {
Adam Powellfcca00a2010-11-30 21:26:29 -0800444 final int count = getVirtualChildCount();
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700445 final boolean isLayoutRtl = isLayoutRtl();
Adam Powellfcca00a2010-11-30 21:26:29 -0800446 for (int i = 0; i < count; i++) {
447 final View child = getVirtualChildAt(i);
Adam Powell35aecd52011-07-01 13:43:49 -0700448 if (child != null && child.getVisibility() != GONE) {
Adam Powell696cba52011-03-29 10:38:16 -0700449 if (hasDividerBeforeChildAt(i)) {
Adam Powell35aecd52011-07-01 13:43:49 -0700450 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700451 final int position;
452 if (isLayoutRtl) {
453 position = child.getRight() + lp.rightMargin;
454 } else {
455 position = child.getLeft() - lp.leftMargin - mDividerWidth;
456 }
457 drawVerticalDivider(canvas, position);
Adam Powellfcca00a2010-11-30 21:26:29 -0800458 }
Adam Powellfcca00a2010-11-30 21:26:29 -0800459 }
460 }
461
Adam Powell696cba52011-03-29 10:38:16 -0700462 if (hasDividerBeforeChildAt(count)) {
Doris Liuec6a4cd2015-06-25 15:16:54 -0700463 final View child = getLastNonGoneChild();
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700464 int position;
Adam Powell35aecd52011-07-01 13:43:49 -0700465 if (child == null) {
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700466 if (isLayoutRtl) {
467 position = getPaddingLeft();
468 } else {
469 position = getWidth() - getPaddingRight() - mDividerWidth;
470 }
Adam Powell35aecd52011-07-01 13:43:49 -0700471 } else {
472 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700473 if (isLayoutRtl) {
474 position = child.getLeft() - lp.leftMargin - mDividerWidth;
475 } else {
476 position = child.getRight() + lp.rightMargin;
477 }
Adam Powell35aecd52011-07-01 13:43:49 -0700478 }
Fabrice Di Meglio4ab69682012-07-02 19:12:40 -0700479 drawVerticalDivider(canvas, position);
Adam Powellfcca00a2010-11-30 21:26:29 -0800480 }
481 }
482
483 void drawHorizontalDivider(Canvas canvas, int top) {
484 mDivider.setBounds(getPaddingLeft() + mDividerPadding, top,
485 getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);
486 mDivider.draw(canvas);
487 }
488
489 void drawVerticalDivider(Canvas canvas, int left) {
490 mDivider.setBounds(left, getPaddingTop() + mDividerPadding,
491 left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding);
492 mDivider.draw(canvas);
493 }
494
495 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 * <p>Indicates whether widgets contained within this layout are aligned
497 * on their baseline or not.</p>
498 *
499 * @return true when widgets are baseline-aligned, false otherwise
500 */
501 public boolean isBaselineAligned() {
502 return mBaselineAligned;
503 }
504
505 /**
506 * <p>Defines whether widgets contained in this layout are
507 * baseline-aligned or not.</p>
508 *
509 * @param baselineAligned true to align widgets on their baseline,
510 * false otherwise
511 *
512 * @attr ref android.R.styleable#LinearLayout_baselineAligned
513 */
514 @android.view.RemotableViewMethod
515 public void setBaselineAligned(boolean baselineAligned) {
516 mBaselineAligned = baselineAligned;
517 }
518
Romain Guy9295ada2010-06-15 11:33:24 -0700519 /**
520 * When true, all children with a weight will be considered having
521 * the minimum size of the largest child. If false, all children are
522 * measured normally.
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700523 *
Romain Guy9295ada2010-06-15 11:33:24 -0700524 * @return True to measure children with a weight using the minimum
525 * size of the largest child, false otherwise.
Philip Milne1018fb42012-03-13 12:00:04 -0700526 *
527 * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
Romain Guy9295ada2010-06-15 11:33:24 -0700528 */
529 public boolean isMeasureWithLargestChildEnabled() {
530 return mUseLargestChild;
531 }
532
533 /**
534 * When set to true, all children with a weight will be considered having
535 * the minimum size of the largest child. If false, all children are
536 * measured normally.
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700537 *
Romain Guy9295ada2010-06-15 11:33:24 -0700538 * Disabled by default.
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700539 *
Romain Guy9295ada2010-06-15 11:33:24 -0700540 * @param enabled True to measure children with a weight using the
541 * minimum size of the largest child, false otherwise.
Philip Milne1018fb42012-03-13 12:00:04 -0700542 *
543 * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
Romain Guy9295ada2010-06-15 11:33:24 -0700544 */
545 @android.view.RemotableViewMethod
546 public void setMeasureWithLargestChildEnabled(boolean enabled) {
547 mUseLargestChild = enabled;
548 }
549
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 @Override
551 public int getBaseline() {
552 if (mBaselineAlignedChildIndex < 0) {
553 return super.getBaseline();
554 }
555
556 if (getChildCount() <= mBaselineAlignedChildIndex) {
557 throw new RuntimeException("mBaselineAlignedChildIndex of LinearLayout "
558 + "set to an index that is out of bounds.");
559 }
560
561 final View child = getChildAt(mBaselineAlignedChildIndex);
562 final int childBaseline = child.getBaseline();
563
564 if (childBaseline == -1) {
565 if (mBaselineAlignedChildIndex == 0) {
566 // this is just the default case, safe to return -1
567 return -1;
568 }
569 // the user picked an index that points to something that doesn't
570 // know how to calculate its baseline.
571 throw new RuntimeException("mBaselineAlignedChildIndex of LinearLayout "
572 + "points to a View that doesn't know how to get its baseline.");
573 }
574
575 // TODO: This should try to take into account the virtual offsets
576 // (See getNextLocationOffset and getLocationOffset)
577 // We should add to childTop:
578 // sum([getNextLocationOffset(getChildAt(i)) / i < mBaselineAlignedChildIndex])
579 // and also add:
580 // getLocationOffset(child)
581 int childTop = mBaselineChildTop;
582
583 if (mOrientation == VERTICAL) {
584 final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
585 if (majorGravity != Gravity.TOP) {
586 switch (majorGravity) {
587 case Gravity.BOTTOM:
588 childTop = mBottom - mTop - mPaddingBottom - mTotalLength;
589 break;
590
591 case Gravity.CENTER_VERTICAL:
592 childTop += ((mBottom - mTop - mPaddingTop - mPaddingBottom) -
593 mTotalLength) / 2;
594 break;
595 }
596 }
597 }
598
599 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
600 return childTop + lp.topMargin + childBaseline;
601 }
602
603 /**
604 * @return The index of the child that will be used if this layout is
605 * part of a larger layout that is baseline aligned, or -1 if none has
606 * been set.
607 */
608 public int getBaselineAlignedChildIndex() {
609 return mBaselineAlignedChildIndex;
610 }
611
612 /**
613 * @param i The index of the child that will be used if this layout is
614 * part of a larger layout that is baseline aligned.
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700615 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616 * @attr ref android.R.styleable#LinearLayout_baselineAlignedChildIndex
617 */
618 @android.view.RemotableViewMethod
619 public void setBaselineAlignedChildIndex(int i) {
620 if ((i < 0) || (i >= getChildCount())) {
621 throw new IllegalArgumentException("base aligned child index out "
622 + "of range (0, " + getChildCount() + ")");
623 }
624 mBaselineAlignedChildIndex = i;
625 }
626
627 /**
628 * <p>Returns the view at the specified index. This method can be overriden
629 * to take into account virtual children. Refer to
630 * {@link android.widget.TableLayout} and {@link android.widget.TableRow}
631 * for an example.</p>
632 *
633 * @param index the child's index
Alan Viverettead526932015-12-17 12:42:39 -0500634 * @return the child at the specified index, may be {@code null}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 */
Alan Viverettead526932015-12-17 12:42:39 -0500636 @Nullable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 View getVirtualChildAt(int index) {
638 return getChildAt(index);
639 }
640
641 /**
642 * <p>Returns the virtual number of children. This number might be different
643 * than the actual number of children if the layout can hold virtual
644 * children. Refer to
645 * {@link android.widget.TableLayout} and {@link android.widget.TableRow}
646 * for an example.</p>
647 *
648 * @return the virtual number of children
649 */
650 int getVirtualChildCount() {
651 return getChildCount();
652 }
653
654 /**
655 * Returns the desired weights sum.
656 *
657 * @return A number greater than 0.0f if the weight sum is defined, or
658 * a number lower than or equals to 0.0f if not weight sum is
659 * to be used.
660 */
661 public float getWeightSum() {
662 return mWeightSum;
663 }
664
665 /**
666 * Defines the desired weights sum. If unspecified the weights sum is computed
667 * at layout time by adding the layout_weight of each child.
668 *
669 * This can be used for instance to give a single child 50% of the total
670 * available space by giving it a layout_weight of 0.5 and setting the
671 * weightSum to 1.0.
672 *
673 * @param weightSum a number greater than 0.0f, or a number lower than or equals
674 * to 0.0f if the weight sum should be computed from the children's
675 * layout_weight
676 */
677 @android.view.RemotableViewMethod
678 public void setWeightSum(float weightSum) {
679 mWeightSum = Math.max(0.0f, weightSum);
680 }
681
682 @Override
683 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
684 if (mOrientation == VERTICAL) {
685 measureVertical(widthMeasureSpec, heightMeasureSpec);
686 } else {
687 measureHorizontal(widthMeasureSpec, heightMeasureSpec);
688 }
689 }
690
691 /**
Adam Powell696cba52011-03-29 10:38:16 -0700692 * Determines where to position dividers between children.
693 *
694 * @param childIndex Index of child to check for preceding divider
695 * @return true if there should be a divider before the child at childIndex
696 * @hide Pending API consideration. Currently only used internally by the system.
697 */
698 protected boolean hasDividerBeforeChildAt(int childIndex) {
Doris Liuec6a4cd2015-06-25 15:16:54 -0700699 if (childIndex == getVirtualChildCount()) {
700 // Check whether the end divider should draw.
Adam Powell696cba52011-03-29 10:38:16 -0700701 return (mShowDividers & SHOW_DIVIDER_END) != 0;
Adam Powell696cba52011-03-29 10:38:16 -0700702 }
Doris Liuec6a4cd2015-06-25 15:16:54 -0700703 boolean allViewsAreGoneBefore = allViewsAreGoneBefore(childIndex);
704 if (allViewsAreGoneBefore) {
705 // This is the first view that's not gone, check if beginning divider is enabled.
706 return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0;
707 } else {
708 return (mShowDividers & SHOW_DIVIDER_MIDDLE) != 0;
709 }
710 }
711
712 /**
713 * Checks whether all (virtual) child views before the given index are gone.
714 */
715 private boolean allViewsAreGoneBefore(int childIndex) {
716 for (int i = childIndex - 1; i >= 0; i--) {
Alan Viverettead526932015-12-17 12:42:39 -0500717 final View child = getVirtualChildAt(i);
Doris Liuf102d422015-06-30 13:42:22 -0700718 if (child != null && child.getVisibility() != GONE) {
Doris Liuec6a4cd2015-06-25 15:16:54 -0700719 return false;
720 }
721 }
722 return true;
Adam Powell696cba52011-03-29 10:38:16 -0700723 }
724
725 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 * Measures the children when the orientation of this LinearLayout is set
727 * to {@link #VERTICAL}.
728 *
729 * @param widthMeasureSpec Horizontal space requirements as imposed by the parent.
730 * @param heightMeasureSpec Vertical space requirements as imposed by the parent.
731 *
732 * @see #getOrientation()
733 * @see #setOrientation(int)
734 * @see #onMeasure(int, int)
735 */
736 void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
737 mTotalLength = 0;
738 int maxWidth = 0;
Dianne Hackborn189ee182010-12-02 21:48:53 -0800739 int childState = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 int alternativeMaxWidth = 0;
741 int weightedMaxWidth = 0;
742 boolean allFillParent = true;
743 float totalWeight = 0;
744
745 final int count = getVirtualChildCount();
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700746
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
748 final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
749
750 boolean matchWidth = false;
Alan Viverette65be9cc2014-02-24 18:21:09 -0800751 boolean skippedMeasure = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700753 final int baselineChildIndex = mBaselineAlignedChildIndex;
Romain Guy5b1b2412010-01-21 19:09:51 -0800754 final boolean useLargestChild = mUseLargestChild;
755
756 int largestChildHeight = Integer.MIN_VALUE;
Alan Viverette40e1df32015-08-25 16:50:27 -0400757 int consumedExcessSpace = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400759 int nonSkippedChildCount = 0;
760
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 // See how tall everyone is. Also remember max width.
762 for (int i = 0; i < count; ++i) {
763 final View child = getVirtualChildAt(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 if (child == null) {
765 mTotalLength += measureNullChild(i);
766 continue;
767 }
768
769 if (child.getVisibility() == View.GONE) {
770 i += getChildrenSkipCount(child, i);
771 continue;
772 }
773
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400774 nonSkippedChildCount++;
Adam Powell696cba52011-03-29 10:38:16 -0700775 if (hasDividerBeforeChildAt(i)) {
Adam Powellfcca00a2010-11-30 21:26:29 -0800776 mTotalLength += mDividerHeight;
777 }
778
Alan Viverette40e1df32015-08-25 16:50:27 -0400779 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Alan Viverette61c41bf2016-05-05 17:52:10 +0000780
781 totalWeight += lp.weight;
Alan Viverette40e1df32015-08-25 16:50:27 -0400782
783 final boolean useExcessSpace = lp.height == 0 && lp.weight > 0;
784 if (heightMode == MeasureSpec.EXACTLY && useExcessSpace) {
785 // Optimization: don't bother measuring children who are only
786 // laid out using excess space. These views will get measured
787 // later if we have space to distribute.
Romain Guy053b4802010-02-05 15:34:33 -0800788 final int totalLength = mTotalLength;
789 mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);
Alan Viverette65be9cc2014-02-24 18:21:09 -0800790 skippedMeasure = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800791 } else {
Alan Viverette40e1df32015-08-25 16:50:27 -0400792 if (useExcessSpace) {
793 // The heightMode is either UNSPECIFIED or AT_MOST, and
794 // this child is only laid out using excess space. Measure
795 // using WRAP_CONTENT so that we can find out the view's
796 // optimal height. We'll restore the original height of 0
797 // after measurement.
Gilles Debunnef5c6eff2010-02-09 19:08:36 -0800798 lp.height = LayoutParams.WRAP_CONTENT;
Romain Guy5b1b2412010-01-21 19:09:51 -0800799 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800
Gilles Debunnef5c6eff2010-02-09 19:08:36 -0800801 // Determine how big this child would like to be. If this or
Romain Guy5b1b2412010-01-21 19:09:51 -0800802 // previous children have given a weight, then we allow it to
803 // use all available space (and we will shrink things later
804 // if needed).
Alan Viverette40e1df32015-08-25 16:50:27 -0400805 final int usedHeight = totalWeight == 0 ? mTotalLength : 0;
806 measureChildBeforeLayout(child, i, widthMeasureSpec, 0,
807 heightMeasureSpec, usedHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800808
Alan Viverette5a969df2015-07-31 12:42:10 -0400809 final int childHeight = child.getMeasuredHeight();
Alan Viverette40e1df32015-08-25 16:50:27 -0400810 if (useExcessSpace) {
811 // Restore the original height and record how much space
812 // we've allocated to excess-only children so that we can
813 // match the behavior of EXACTLY measurement.
814 lp.height = 0;
815 consumedExcessSpace += childHeight;
816 }
817
Romain Guy053b4802010-02-05 15:34:33 -0800818 final int totalLength = mTotalLength;
819 mTotalLength = Math.max(totalLength, totalLength + childHeight + lp.topMargin +
820 lp.bottomMargin + getNextLocationOffset(child));
Romain Guy5b1b2412010-01-21 19:09:51 -0800821
822 if (useLargestChild) {
823 largestChildHeight = Math.max(childHeight, largestChildHeight);
824 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800825 }
826
827 /**
828 * If applicable, compute the additional offset to the child's baseline
829 * we'll need later when asked {@link #getBaseline}.
830 */
831 if ((baselineChildIndex >= 0) && (baselineChildIndex == i + 1)) {
832 mBaselineChildTop = mTotalLength;
833 }
834
835 // if we are trying to use a child index for our baseline, the above
836 // book keeping only works if there are no children above it with
837 // weight. fail fast to aid the developer.
838 if (i < baselineChildIndex && lp.weight > 0) {
839 throw new RuntimeException("A child of LinearLayout with index "
840 + "less than mBaselineAlignedChildIndex has weight > 0, which "
841 + "won't work. Either remove the weight, or don't set "
842 + "mBaselineAlignedChildIndex.");
843 }
844
845 boolean matchWidthLocally = false;
Romain Guy980a9382010-01-08 15:06:28 -0800846 if (widthMode != MeasureSpec.EXACTLY && lp.width == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847 // The width of the linear layout will scale, and at least one
848 // child said it wanted to match our width. Set a flag
849 // indicating that we need to remeasure at least that view when
850 // we know our width.
851 matchWidth = true;
852 matchWidthLocally = true;
853 }
854
855 final int margin = lp.leftMargin + lp.rightMargin;
856 final int measuredWidth = child.getMeasuredWidth() + margin;
857 maxWidth = Math.max(maxWidth, measuredWidth);
Dianne Hackborn189ee182010-12-02 21:48:53 -0800858 childState = combineMeasuredStates(childState, child.getMeasuredState());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859
Romain Guy980a9382010-01-08 15:06:28 -0800860 allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 if (lp.weight > 0) {
862 /*
863 * Widths of weighted Views are bogus if we end up
864 * remeasuring, so keep them separate.
865 */
866 weightedMaxWidth = Math.max(weightedMaxWidth,
867 matchWidthLocally ? margin : measuredWidth);
868 } else {
869 alternativeMaxWidth = Math.max(alternativeMaxWidth,
870 matchWidthLocally ? margin : measuredWidth);
871 }
872
873 i += getChildrenSkipCount(child, i);
874 }
Romain Guy5b1b2412010-01-21 19:09:51 -0800875
Kirill Grouchnikov9df08462016-04-26 15:28:25 -0400876 if (nonSkippedChildCount > 0 && hasDividerBeforeChildAt(count)) {
Adam Powellfcca00a2010-11-30 21:26:29 -0800877 mTotalLength += mDividerHeight;
878 }
879
Adam Powellf8ac6b72011-05-23 18:14:09 -0700880 if (useLargestChild &&
881 (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED)) {
Romain Guy5b1b2412010-01-21 19:09:51 -0800882 mTotalLength = 0;
883
884 for (int i = 0; i < count; ++i) {
885 final View child = getVirtualChildAt(i);
Romain Guy5b1b2412010-01-21 19:09:51 -0800886 if (child == null) {
887 mTotalLength += measureNullChild(i);
888 continue;
889 }
890
891 if (child.getVisibility() == GONE) {
892 i += getChildrenSkipCount(child, i);
893 continue;
894 }
895
896 final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
897 child.getLayoutParams();
Romain Guy053b4802010-02-05 15:34:33 -0800898 // Account for negative margins
899 final int totalLength = mTotalLength;
900 mTotalLength = Math.max(totalLength, totalLength + largestChildHeight +
901 lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));
Romain Guy5b1b2412010-01-21 19:09:51 -0800902 }
903 }
904
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 // Add in our padding
906 mTotalLength += mPaddingTop + mPaddingBottom;
907
908 int heightSize = mTotalLength;
909
910 // Check against our minimum height
911 heightSize = Math.max(heightSize, getSuggestedMinimumHeight());
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700912
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800913 // Reconcile our calculated size with the heightMeasureSpec
Dianne Hackborn189ee182010-12-02 21:48:53 -0800914 int heightSizeAndState = resolveSizeAndState(heightSize, heightMeasureSpec, 0);
915 heightSize = heightSizeAndState & MEASURED_SIZE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916 // Either expand children with weight to take up available space or
Alan Viverette65be9cc2014-02-24 18:21:09 -0800917 // shrink them if they extend beyond our current bounds. If we skipped
918 // measurement on any children, we need to measure them now.
Alan Viverette918f8862016-03-17 12:28:31 -0400919 int remainingExcess = heightSize - mTotalLength
Alan Viverette40e1df32015-08-25 16:50:27 -0400920 + (mAllowInconsistentMeasurement ? 0 : consumedExcessSpace);
Alan Viverette918f8862016-03-17 12:28:31 -0400921 if (skippedMeasure || remainingExcess != 0 && totalWeight > 0.0f) {
922 float remainingWeightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923
924 mTotalLength = 0;
925
926 for (int i = 0; i < count; ++i) {
927 final View child = getVirtualChildAt(i);
Alan Viverette40e1df32015-08-25 16:50:27 -0400928 if (child == null || child.getVisibility() == View.GONE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800929 continue;
930 }
Alan Viverette40e1df32015-08-25 16:50:27 -0400931
932 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Alan Viverette918f8862016-03-17 12:28:31 -0400933 final float childWeight = lp.weight;
934 if (childWeight > 0) {
Alan Viverette61c41bf2016-05-05 17:52:10 +0000935 final int share = (int) (childWeight * remainingExcess / remainingWeightSum);
Alan Viverette918f8862016-03-17 12:28:31 -0400936 remainingExcess -= share;
937 remainingWeightSum -= childWeight;
938
Alan Viverette40e1df32015-08-25 16:50:27 -0400939 final int childHeight;
Alan Viverette070b22b2016-06-30 11:15:36 -0400940 if (mUseLargestChild && heightMode != MeasureSpec.EXACTLY) {
941 childHeight = largestChildHeight;
942 } else if (lp.height == 0 && (!mAllowInconsistentMeasurement
Alan Viverette40e1df32015-08-25 16:50:27 -0400943 || heightMode == MeasureSpec.EXACTLY)) {
944 // This child needs to be laid out from scratch using
945 // only its share of excess space.
946 childHeight = share;
Alan Viverette5a969df2015-07-31 12:42:10 -0400947 } else {
Alan Viverette40e1df32015-08-25 16:50:27 -0400948 // This child had some intrinsic height to which we
949 // need to add its share of excess space.
950 childHeight = child.getMeasuredHeight() + share;
Alan Viverette5a969df2015-07-31 12:42:10 -0400951 }
Dianne Hackborn189ee182010-12-02 21:48:53 -0800952
Alan Viverette40e1df32015-08-25 16:50:27 -0400953 final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
954 Math.max(0, childHeight), MeasureSpec.EXACTLY);
955 final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
956 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin,
957 lp.width);
958 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
959
Dianne Hackborn189ee182010-12-02 21:48:53 -0800960 // Child may now not fit in vertical dimension.
961 childState = combineMeasuredStates(childState, child.getMeasuredState()
962 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 }
964
965 final int margin = lp.leftMargin + lp.rightMargin;
966 final int measuredWidth = child.getMeasuredWidth() + margin;
967 maxWidth = Math.max(maxWidth, measuredWidth);
968
969 boolean matchWidthLocally = widthMode != MeasureSpec.EXACTLY &&
Romain Guy980a9382010-01-08 15:06:28 -0800970 lp.width == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800971
972 alternativeMaxWidth = Math.max(alternativeMaxWidth,
973 matchWidthLocally ? margin : measuredWidth);
974
Romain Guy980a9382010-01-08 15:06:28 -0800975 allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976
Romain Guy053b4802010-02-05 15:34:33 -0800977 final int totalLength = mTotalLength;
978 mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredHeight() +
979 lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 }
981
982 // Add in our padding
Romain Guy053b4802010-02-05 15:34:33 -0800983 mTotalLength += mPaddingTop + mPaddingBottom;
984 // TODO: Should we recompute the heightSpec based on the new total length?
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800985 } else {
986 alternativeMaxWidth = Math.max(alternativeMaxWidth,
987 weightedMaxWidth);
Adam Powellf8ac6b72011-05-23 18:14:09 -0700988
989
990 // We have no limit, so make all weighted views as tall as the largest child.
991 // Children will have already been measured once.
Adam Powelleabc9192012-05-04 14:49:46 -0700992 if (useLargestChild && heightMode != MeasureSpec.EXACTLY) {
Adam Powellf8ac6b72011-05-23 18:14:09 -0700993 for (int i = 0; i < count; i++) {
994 final View child = getVirtualChildAt(i);
Adam Powellf8ac6b72011-05-23 18:14:09 -0700995 if (child == null || child.getVisibility() == View.GONE) {
996 continue;
997 }
998
999 final LinearLayout.LayoutParams lp =
1000 (LinearLayout.LayoutParams) child.getLayoutParams();
1001
1002 float childExtra = lp.weight;
1003 if (childExtra > 0) {
1004 child.measure(
1005 MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(),
1006 MeasureSpec.EXACTLY),
1007 MeasureSpec.makeMeasureSpec(largestChildHeight,
1008 MeasureSpec.EXACTLY));
1009 }
1010 }
1011 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 }
1013
1014 if (!allFillParent && widthMode != MeasureSpec.EXACTLY) {
1015 maxWidth = alternativeMaxWidth;
1016 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001017
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018 maxWidth += mPaddingLeft + mPaddingRight;
1019
1020 // Check against our minimum width
1021 maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001022
Dianne Hackborn189ee182010-12-02 21:48:53 -08001023 setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
1024 heightSizeAndState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025
1026 if (matchWidth) {
1027 forceUniformWidth(count, heightMeasureSpec);
1028 }
1029 }
1030
1031 private void forceUniformWidth(int count, int heightMeasureSpec) {
1032 // Pretend that the linear layout has an exact size.
1033 int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(),
1034 MeasureSpec.EXACTLY);
1035 for (int i = 0; i< count; ++i) {
1036 final View child = getVirtualChildAt(i);
Alan Viverettead526932015-12-17 12:42:39 -05001037 if (child != null && child.getVisibility() != GONE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001038 LinearLayout.LayoutParams lp = ((LinearLayout.LayoutParams)child.getLayoutParams());
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001039
Romain Guy980a9382010-01-08 15:06:28 -08001040 if (lp.width == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041 // Temporarily force children to reuse their old measured height
1042 // FIXME: this may not be right for something like wrapping text?
1043 int oldHeight = lp.height;
1044 lp.height = child.getMeasuredHeight();
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001045
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 // Remeasue with new dimensions
1047 measureChildWithMargins(child, uniformMeasureSpec, 0, heightMeasureSpec, 0);
1048 lp.height = oldHeight;
1049 }
1050 }
1051 }
1052 }
1053
1054 /**
1055 * Measures the children when the orientation of this LinearLayout is set
1056 * to {@link #HORIZONTAL}.
1057 *
1058 * @param widthMeasureSpec Horizontal space requirements as imposed by the parent.
1059 * @param heightMeasureSpec Vertical space requirements as imposed by the parent.
1060 *
1061 * @see #getOrientation()
1062 * @see #setOrientation(int)
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001063 * @see #onMeasure(int, int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 */
1065 void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec) {
1066 mTotalLength = 0;
1067 int maxHeight = 0;
Dianne Hackborn189ee182010-12-02 21:48:53 -08001068 int childState = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001069 int alternativeMaxHeight = 0;
1070 int weightedMaxHeight = 0;
1071 boolean allFillParent = true;
1072 float totalWeight = 0;
1073
1074 final int count = getVirtualChildCount();
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001075
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001076 final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
1077 final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
1078
1079 boolean matchHeight = false;
Alan Viverette65be9cc2014-02-24 18:21:09 -08001080 boolean skippedMeasure = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001081
1082 if (mMaxAscent == null || mMaxDescent == null) {
1083 mMaxAscent = new int[VERTICAL_GRAVITY_COUNT];
1084 mMaxDescent = new int[VERTICAL_GRAVITY_COUNT];
1085 }
1086
1087 final int[] maxAscent = mMaxAscent;
1088 final int[] maxDescent = mMaxDescent;
1089
1090 maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
1091 maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;
1092
1093 final boolean baselineAligned = mBaselineAligned;
Romain Guy5b1b2412010-01-21 19:09:51 -08001094 final boolean useLargestChild = mUseLargestChild;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001095
Romain Guyc3520902010-02-25 11:01:01 -08001096 final boolean isExactly = widthMode == MeasureSpec.EXACTLY;
Romain Guy5b1b2412010-01-21 19:09:51 -08001097
1098 int largestChildWidth = Integer.MIN_VALUE;
Alan Viverette40e1df32015-08-25 16:50:27 -04001099 int usedExcessSpace = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001100
Kirill Grouchnikov9df08462016-04-26 15:28:25 -04001101 int nonSkippedChildCount = 0;
1102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 // See how wide everyone is. Also remember max height.
1104 for (int i = 0; i < count; ++i) {
1105 final View child = getVirtualChildAt(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001106 if (child == null) {
1107 mTotalLength += measureNullChild(i);
1108 continue;
1109 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001110
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001111 if (child.getVisibility() == GONE) {
1112 i += getChildrenSkipCount(child, i);
1113 continue;
1114 }
1115
Kirill Grouchnikov9df08462016-04-26 15:28:25 -04001116 nonSkippedChildCount++;
Adam Powell696cba52011-03-29 10:38:16 -07001117 if (hasDividerBeforeChildAt(i)) {
Adam Powellfcca00a2010-11-30 21:26:29 -08001118 mTotalLength += mDividerWidth;
1119 }
1120
Alan Viverette40e1df32015-08-25 16:50:27 -04001121 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Alan Viverette61c41bf2016-05-05 17:52:10 +00001122
1123 totalWeight += lp.weight;
Alan Viverette40e1df32015-08-25 16:50:27 -04001124
1125 final boolean useExcessSpace = lp.width == 0 && lp.weight > 0;
1126 if (widthMode == MeasureSpec.EXACTLY && useExcessSpace) {
1127 // Optimization: don't bother measuring children who are only
1128 // laid out using excess space. These views will get measured
1129 // later if we have space to distribute.
Romain Guyc3520902010-02-25 11:01:01 -08001130 if (isExactly) {
1131 mTotalLength += lp.leftMargin + lp.rightMargin;
1132 } else {
1133 final int totalLength = mTotalLength;
1134 mTotalLength = Math.max(totalLength, totalLength +
1135 lp.leftMargin + lp.rightMargin);
1136 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137
1138 // Baseline alignment requires to measure widgets to obtain the
Romain Guy6c5664a2010-02-24 18:55:22 -08001139 // baseline offset (in particular for TextViews). The following
1140 // defeats the optimization mentioned above. Allow the child to
1141 // use as much space as it wants because we can shrink things
1142 // later (and re-measure).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143 if (baselineAligned) {
Adam Powelld5dbf4b2015-06-11 13:19:24 -07001144 final int freeWidthSpec = MeasureSpec.makeSafeMeasureSpec(
Filip Gruszczynskib6824bf2015-04-13 09:16:25 -07001145 MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.UNSPECIFIED);
Adam Powelld5dbf4b2015-06-11 13:19:24 -07001146 final int freeHeightSpec = MeasureSpec.makeSafeMeasureSpec(
Filip Gruszczynskib6824bf2015-04-13 09:16:25 -07001147 MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED);
1148 child.measure(freeWidthSpec, freeHeightSpec);
Alan Viverette65be9cc2014-02-24 18:21:09 -08001149 } else {
1150 skippedMeasure = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151 }
1152 } else {
Alan Viverette40e1df32015-08-25 16:50:27 -04001153 if (useExcessSpace) {
1154 // The widthMode is either UNSPECIFIED or AT_MOST, and
1155 // this child is only laid out using excess space. Measure
1156 // using WRAP_CONTENT so that we can find out the view's
1157 // optimal width. We'll restore the original width of 0
1158 // after measurement.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001159 lp.width = LayoutParams.WRAP_CONTENT;
1160 }
1161
1162 // Determine how big this child would like to be. If this or
1163 // previous children have given a weight, then we allow it to
1164 // use all available space (and we will shrink things later
1165 // if needed).
Alan Viverette40e1df32015-08-25 16:50:27 -04001166 final int usedWidth = totalWeight == 0 ? mTotalLength : 0;
1167 measureChildBeforeLayout(child, i, widthMeasureSpec, usedWidth,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001168 heightMeasureSpec, 0);
1169
Alan Viverette40e1df32015-08-25 16:50:27 -04001170 final int childWidth = child.getMeasuredWidth();
1171 if (useExcessSpace) {
1172 // Restore the original width and record how much space
1173 // we've allocated to excess-only children so that we can
1174 // match the behavior of EXACTLY measurement.
1175 lp.width = 0;
1176 usedExcessSpace += childWidth;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177 }
Romain Guy5b1b2412010-01-21 19:09:51 -08001178
Romain Guyc3520902010-02-25 11:01:01 -08001179 if (isExactly) {
Alan Viverette40e1df32015-08-25 16:50:27 -04001180 mTotalLength += childWidth + lp.leftMargin + lp.rightMargin
1181 + getNextLocationOffset(child);
Romain Guyc3520902010-02-25 11:01:01 -08001182 } else {
1183 final int totalLength = mTotalLength;
Alan Viverette40e1df32015-08-25 16:50:27 -04001184 mTotalLength = Math.max(totalLength, totalLength + childWidth + lp.leftMargin
1185 + lp.rightMargin + getNextLocationOffset(child));
Romain Guyc3520902010-02-25 11:01:01 -08001186 }
Romain Guy5b1b2412010-01-21 19:09:51 -08001187
1188 if (useLargestChild) {
1189 largestChildWidth = Math.max(childWidth, largestChildWidth);
1190 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191 }
1192
1193 boolean matchHeightLocally = false;
Romain Guy980a9382010-01-08 15:06:28 -08001194 if (heightMode != MeasureSpec.EXACTLY && lp.height == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195 // The height of the linear layout will scale, and at least one
1196 // child said it wanted to match our height. Set a flag indicating that
1197 // we need to remeasure at least that view when we know our height.
1198 matchHeight = true;
1199 matchHeightLocally = true;
1200 }
1201
1202 final int margin = lp.topMargin + lp.bottomMargin;
1203 final int childHeight = child.getMeasuredHeight() + margin;
Dianne Hackborn189ee182010-12-02 21:48:53 -08001204 childState = combineMeasuredStates(childState, child.getMeasuredState());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001205
1206 if (baselineAligned) {
1207 final int childBaseline = child.getBaseline();
1208 if (childBaseline != -1) {
1209 // Translates the child's vertical gravity into an index
1210 // in the range 0..VERTICAL_GRAVITY_COUNT
1211 final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity)
1212 & Gravity.VERTICAL_GRAVITY_MASK;
1213 final int index = ((gravity >> Gravity.AXIS_Y_SHIFT)
1214 & ~Gravity.AXIS_SPECIFIED) >> 1;
1215
1216 maxAscent[index] = Math.max(maxAscent[index], childBaseline);
1217 maxDescent[index] = Math.max(maxDescent[index], childHeight - childBaseline);
1218 }
1219 }
1220
1221 maxHeight = Math.max(maxHeight, childHeight);
1222
Romain Guy980a9382010-01-08 15:06:28 -08001223 allFillParent = allFillParent && lp.height == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001224 if (lp.weight > 0) {
1225 /*
1226 * Heights of weighted Views are bogus if we end up
1227 * remeasuring, so keep them separate.
1228 */
1229 weightedMaxHeight = Math.max(weightedMaxHeight,
1230 matchHeightLocally ? margin : childHeight);
1231 } else {
1232 alternativeMaxHeight = Math.max(alternativeMaxHeight,
1233 matchHeightLocally ? margin : childHeight);
1234 }
1235
1236 i += getChildrenSkipCount(child, i);
1237 }
1238
Kirill Grouchnikov9df08462016-04-26 15:28:25 -04001239 if (nonSkippedChildCount > 0 && hasDividerBeforeChildAt(count)) {
Adam Powellfcca00a2010-11-30 21:26:29 -08001240 mTotalLength += mDividerWidth;
1241 }
1242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001243 // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP,
1244 // the most common case
1245 if (maxAscent[INDEX_TOP] != -1 ||
1246 maxAscent[INDEX_CENTER_VERTICAL] != -1 ||
1247 maxAscent[INDEX_BOTTOM] != -1 ||
1248 maxAscent[INDEX_FILL] != -1) {
1249 final int ascent = Math.max(maxAscent[INDEX_FILL],
1250 Math.max(maxAscent[INDEX_CENTER_VERTICAL],
1251 Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM])));
1252 final int descent = Math.max(maxDescent[INDEX_FILL],
1253 Math.max(maxDescent[INDEX_CENTER_VERTICAL],
1254 Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM])));
1255 maxHeight = Math.max(maxHeight, ascent + descent);
1256 }
1257
Adam Powellf8ac6b72011-05-23 18:14:09 -07001258 if (useLargestChild &&
1259 (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.UNSPECIFIED)) {
Romain Guy5b1b2412010-01-21 19:09:51 -08001260 mTotalLength = 0;
1261
1262 for (int i = 0; i < count; ++i) {
1263 final View child = getVirtualChildAt(i);
Romain Guy5b1b2412010-01-21 19:09:51 -08001264 if (child == null) {
1265 mTotalLength += measureNullChild(i);
1266 continue;
1267 }
1268
1269 if (child.getVisibility() == GONE) {
1270 i += getChildrenSkipCount(child, i);
1271 continue;
1272 }
1273
1274 final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
1275 child.getLayoutParams();
Romain Guyc3520902010-02-25 11:01:01 -08001276 if (isExactly) {
1277 mTotalLength += largestChildWidth + lp.leftMargin + lp.rightMargin +
1278 getNextLocationOffset(child);
1279 } else {
1280 final int totalLength = mTotalLength;
1281 mTotalLength = Math.max(totalLength, totalLength + largestChildWidth +
1282 lp.leftMargin + lp.rightMargin + getNextLocationOffset(child));
1283 }
Romain Guy5b1b2412010-01-21 19:09:51 -08001284 }
1285 }
1286
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001287 // Add in our padding
1288 mTotalLength += mPaddingLeft + mPaddingRight;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001289
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001290 int widthSize = mTotalLength;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001291
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001292 // Check against our minimum width
1293 widthSize = Math.max(widthSize, getSuggestedMinimumWidth());
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001294
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001295 // Reconcile our calculated size with the widthMeasureSpec
Dianne Hackborn189ee182010-12-02 21:48:53 -08001296 int widthSizeAndState = resolveSizeAndState(widthSize, widthMeasureSpec, 0);
1297 widthSize = widthSizeAndState & MEASURED_SIZE_MASK;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001298
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001299 // Either expand children with weight to take up available space or
Alan Viverette65be9cc2014-02-24 18:21:09 -08001300 // shrink them if they extend beyond our current bounds. If we skipped
1301 // measurement on any children, we need to measure them now.
Alan Viverette918f8862016-03-17 12:28:31 -04001302 int remainingExcess = widthSize - mTotalLength
Alan Viverette40e1df32015-08-25 16:50:27 -04001303 + (mAllowInconsistentMeasurement ? 0 : usedExcessSpace);
Alan Viverette918f8862016-03-17 12:28:31 -04001304 if (skippedMeasure || remainingExcess != 0 && totalWeight > 0.0f) {
1305 float remainingWeightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306
1307 maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
1308 maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;
1309 maxHeight = -1;
1310
1311 mTotalLength = 0;
1312
1313 for (int i = 0; i < count; ++i) {
1314 final View child = getVirtualChildAt(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001315 if (child == null || child.getVisibility() == View.GONE) {
1316 continue;
1317 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318
Alan Viverette40e1df32015-08-25 16:50:27 -04001319 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
Alan Viverette918f8862016-03-17 12:28:31 -04001320 final float childWeight = lp.weight;
1321 if (childWeight > 0) {
Alan Viverette61c41bf2016-05-05 17:52:10 +00001322 final int share = (int) (childWeight * remainingExcess / remainingWeightSum);
Alan Viverette918f8862016-03-17 12:28:31 -04001323 remainingExcess -= share;
1324 remainingWeightSum -= childWeight;
1325
Alan Viverette40e1df32015-08-25 16:50:27 -04001326 final int childWidth;
Alan Viverette070b22b2016-06-30 11:15:36 -04001327 if (mUseLargestChild && widthMode != MeasureSpec.EXACTLY) {
1328 childWidth = largestChildWidth;
1329 } else if (lp.width == 0 && (!mAllowInconsistentMeasurement
Alan Viverette40e1df32015-08-25 16:50:27 -04001330 || widthMode == MeasureSpec.EXACTLY)) {
1331 // This child needs to be laid out from scratch using
1332 // only its share of excess space.
1333 childWidth = share;
1334 } else {
1335 // This child had some intrinsic width to which we
1336 // need to add its share of excess space.
1337 childWidth = child.getMeasuredWidth() + share;
1338 }
Alan Viverette5a969df2015-07-31 12:42:10 -04001339
Alan Viverette40e1df32015-08-25 16:50:27 -04001340 final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
1341 Math.max(0, childWidth), MeasureSpec.EXACTLY);
1342 final int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001343 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin,
1344 lp.height);
Alan Viverette40e1df32015-08-25 16:50:27 -04001345 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn189ee182010-12-02 21:48:53 -08001346
1347 // Child may now not fit in horizontal dimension.
1348 childState = combineMeasuredStates(childState,
1349 child.getMeasuredState() & MEASURED_STATE_MASK);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001350 }
1351
Romain Guyc3520902010-02-25 11:01:01 -08001352 if (isExactly) {
1353 mTotalLength += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin +
1354 getNextLocationOffset(child);
1355 } else {
1356 final int totalLength = mTotalLength;
1357 mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredWidth() +
1358 lp.leftMargin + lp.rightMargin + getNextLocationOffset(child));
1359 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001360
1361 boolean matchHeightLocally = heightMode != MeasureSpec.EXACTLY &&
Romain Guy980a9382010-01-08 15:06:28 -08001362 lp.height == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001363
1364 final int margin = lp.topMargin + lp .bottomMargin;
1365 int childHeight = child.getMeasuredHeight() + margin;
1366 maxHeight = Math.max(maxHeight, childHeight);
1367 alternativeMaxHeight = Math.max(alternativeMaxHeight,
1368 matchHeightLocally ? margin : childHeight);
1369
Romain Guy980a9382010-01-08 15:06:28 -08001370 allFillParent = allFillParent && lp.height == LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371
1372 if (baselineAligned) {
1373 final int childBaseline = child.getBaseline();
1374 if (childBaseline != -1) {
1375 // Translates the child's vertical gravity into an index in the range 0..2
1376 final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity)
1377 & Gravity.VERTICAL_GRAVITY_MASK;
1378 final int index = ((gravity >> Gravity.AXIS_Y_SHIFT)
1379 & ~Gravity.AXIS_SPECIFIED) >> 1;
1380
1381 maxAscent[index] = Math.max(maxAscent[index], childBaseline);
1382 maxDescent[index] = Math.max(maxDescent[index],
1383 childHeight - childBaseline);
1384 }
1385 }
1386 }
1387
1388 // Add in our padding
1389 mTotalLength += mPaddingLeft + mPaddingRight;
Romain Guy053b4802010-02-05 15:34:33 -08001390 // TODO: Should we update widthSize with the new total length?
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001391
1392 // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP,
1393 // the most common case
1394 if (maxAscent[INDEX_TOP] != -1 ||
1395 maxAscent[INDEX_CENTER_VERTICAL] != -1 ||
1396 maxAscent[INDEX_BOTTOM] != -1 ||
1397 maxAscent[INDEX_FILL] != -1) {
1398 final int ascent = Math.max(maxAscent[INDEX_FILL],
1399 Math.max(maxAscent[INDEX_CENTER_VERTICAL],
1400 Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM])));
1401 final int descent = Math.max(maxDescent[INDEX_FILL],
1402 Math.max(maxDescent[INDEX_CENTER_VERTICAL],
1403 Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM])));
1404 maxHeight = Math.max(maxHeight, ascent + descent);
1405 }
1406 } else {
1407 alternativeMaxHeight = Math.max(alternativeMaxHeight, weightedMaxHeight);
Adam Powellf8ac6b72011-05-23 18:14:09 -07001408
1409 // We have no limit, so make all weighted views as wide as the largest child.
1410 // Children will have already been measured once.
Adam Powelleabc9192012-05-04 14:49:46 -07001411 if (useLargestChild && widthMode != MeasureSpec.EXACTLY) {
Adam Powellf8ac6b72011-05-23 18:14:09 -07001412 for (int i = 0; i < count; i++) {
1413 final View child = getVirtualChildAt(i);
Adam Powellf8ac6b72011-05-23 18:14:09 -07001414 if (child == null || child.getVisibility() == View.GONE) {
1415 continue;
1416 }
1417
1418 final LinearLayout.LayoutParams lp =
1419 (LinearLayout.LayoutParams) child.getLayoutParams();
1420
1421 float childExtra = lp.weight;
1422 if (childExtra > 0) {
1423 child.measure(
1424 MeasureSpec.makeMeasureSpec(largestChildWidth, MeasureSpec.EXACTLY),
1425 MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(),
1426 MeasureSpec.EXACTLY));
1427 }
1428 }
1429 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001430 }
1431
1432 if (!allFillParent && heightMode != MeasureSpec.EXACTLY) {
1433 maxHeight = alternativeMaxHeight;
1434 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001435
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001436 maxHeight += mPaddingTop + mPaddingBottom;
1437
1438 // Check against our minimum height
1439 maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001440
Dianne Hackborn189ee182010-12-02 21:48:53 -08001441 setMeasuredDimension(widthSizeAndState | (childState&MEASURED_STATE_MASK),
1442 resolveSizeAndState(maxHeight, heightMeasureSpec,
1443 (childState<<MEASURED_HEIGHT_STATE_SHIFT)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001444
1445 if (matchHeight) {
1446 forceUniformHeight(count, widthMeasureSpec);
1447 }
1448 }
1449
1450 private void forceUniformHeight(int count, int widthMeasureSpec) {
1451 // Pretend that the linear layout has an exact size. This is the measured height of
1452 // ourselves. The measured height should be the max height of the children, changed
Fabrice Di Megliofc53e582012-10-25 11:45:04 -07001453 // to accommodate the heightMeasureSpec from the parent
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001454 int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(),
1455 MeasureSpec.EXACTLY);
1456 for (int i = 0; i < count; ++i) {
1457 final View child = getVirtualChildAt(i);
Alan Viverettead526932015-12-17 12:42:39 -05001458 if (child != null && child.getVisibility() != GONE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001459 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001460
Romain Guy980a9382010-01-08 15:06:28 -08001461 if (lp.height == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001462 // Temporarily force children to reuse their old measured width
1463 // FIXME: this may not be right for something like wrapping text?
1464 int oldWidth = lp.width;
1465 lp.width = child.getMeasuredWidth();
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001467 // Remeasure with new dimensions
1468 measureChildWithMargins(child, widthMeasureSpec, 0, uniformMeasureSpec, 0);
1469 lp.width = oldWidth;
1470 }
1471 }
1472 }
1473 }
1474
1475 /**
1476 * <p>Returns the number of children to skip after measuring/laying out
1477 * the specified child.</p>
1478 *
1479 * @param child the child after which we want to skip children
1480 * @param index the index of the child after which we want to skip children
1481 * @return the number of children to skip, 0 by default
1482 */
1483 int getChildrenSkipCount(View child, int index) {
1484 return 0;
1485 }
1486
1487 /**
1488 * <p>Returns the size (width or height) that should be occupied by a null
1489 * child.</p>
1490 *
1491 * @param childIndex the index of the null child
1492 * @return the width or height of the child depending on the orientation
1493 */
1494 int measureNullChild(int childIndex) {
1495 return 0;
1496 }
1497
1498 /**
1499 * <p>Measure the child according to the parent's measure specs. This
1500 * method should be overriden by subclasses to force the sizing of
1501 * children. This method is called by {@link #measureVertical(int, int)} and
1502 * {@link #measureHorizontal(int, int)}.</p>
1503 *
1504 * @param child the child to measure
1505 * @param childIndex the index of the child in this view
1506 * @param widthMeasureSpec horizontal space requirements as imposed by the parent
1507 * @param totalWidth extra space that has been used up by the parent horizontally
1508 * @param heightMeasureSpec vertical space requirements as imposed by the parent
1509 * @param totalHeight extra space that has been used up by the parent vertically
1510 */
1511 void measureChildBeforeLayout(View child, int childIndex,
1512 int widthMeasureSpec, int totalWidth, int heightMeasureSpec,
1513 int totalHeight) {
1514 measureChildWithMargins(child, widthMeasureSpec, totalWidth,
1515 heightMeasureSpec, totalHeight);
1516 }
1517
1518 /**
1519 * <p>Return the location offset of the specified child. This can be used
1520 * by subclasses to change the location of a given widget.</p>
1521 *
1522 * @param child the child for which to obtain the location offset
1523 * @return the location offset in pixels
1524 */
1525 int getLocationOffset(View child) {
1526 return 0;
1527 }
1528
1529 /**
1530 * <p>Return the size offset of the next sibling of the specified child.
1531 * This can be used by subclasses to change the location of the widget
1532 * following <code>child</code>.</p>
1533 *
1534 * @param child the child whose next sibling will be moved
1535 * @return the location offset of the next child in pixels
1536 */
1537 int getNextLocationOffset(View child) {
1538 return 0;
1539 }
1540
1541 @Override
1542 protected void onLayout(boolean changed, int l, int t, int r, int b) {
1543 if (mOrientation == VERTICAL) {
Philip Milnead365cc2012-09-27 14:38:46 -07001544 layoutVertical(l, t, r, b);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001545 } else {
Philip Milnead365cc2012-09-27 14:38:46 -07001546 layoutHorizontal(l, t, r, b);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001547 }
1548 }
1549
1550 /**
1551 * Position the children during a layout pass if the orientation of this
1552 * LinearLayout is set to {@link #VERTICAL}.
1553 *
1554 * @see #getOrientation()
1555 * @see #setOrientation(int)
1556 * @see #onLayout(boolean, int, int, int, int)
Philip Milnead365cc2012-09-27 14:38:46 -07001557 * @param left
1558 * @param top
1559 * @param right
1560 * @param bottom
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001561 */
Philip Milnead365cc2012-09-27 14:38:46 -07001562 void layoutVertical(int left, int top, int right, int bottom) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001563 final int paddingLeft = mPaddingLeft;
1564
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001565 int childTop;
Romain Guy5b1b2412010-01-21 19:09:51 -08001566 int childLeft;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001567
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001568 // Where right end of child should go
Philip Milnead365cc2012-09-27 14:38:46 -07001569 final int width = right - left;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001570 int childRight = width - mPaddingRight;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001571
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001572 // Space available for child
1573 int childSpace = width - paddingLeft - mPaddingRight;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001574
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001575 final int count = getVirtualChildCount();
1576
1577 final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
Fabrice Di Meglio6a036402011-05-23 14:43:23 -07001578 final int minorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001579
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001580 switch (majorGravity) {
1581 case Gravity.BOTTOM:
1582 // mTotalLength contains the padding already
Philip Milnead365cc2012-09-27 14:38:46 -07001583 childTop = mPaddingTop + bottom - top - mTotalLength;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001584 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001586 // mTotalLength contains the padding already
1587 case Gravity.CENTER_VERTICAL:
Philip Milnead365cc2012-09-27 14:38:46 -07001588 childTop = mPaddingTop + (bottom - top - mTotalLength) / 2;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001589 break;
1590
1591 case Gravity.TOP:
1592 default:
1593 childTop = mPaddingTop;
1594 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001595 }
Adam Powellfcca00a2010-11-30 21:26:29 -08001596
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001597 for (int i = 0; i < count; i++) {
1598 final View child = getVirtualChildAt(i);
1599 if (child == null) {
1600 childTop += measureNullChild(i);
1601 } else if (child.getVisibility() != GONE) {
1602 final int childWidth = child.getMeasuredWidth();
1603 final int childHeight = child.getMeasuredHeight();
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001604
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001605 final LinearLayout.LayoutParams lp =
1606 (LinearLayout.LayoutParams) child.getLayoutParams();
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001607
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001608 int gravity = lp.gravity;
1609 if (gravity < 0) {
1610 gravity = minorGravity;
1611 }
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07001612 final int layoutDirection = getLayoutDirection();
Fabrice Di Meglioc0053222011-06-13 12:16:51 -07001613 final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
Fabrice Di Megliode35cee2011-06-01 15:13:50 -07001614 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001615 case Gravity.CENTER_HORIZONTAL:
1616 childLeft = paddingLeft + ((childSpace - childWidth) / 2)
1617 + lp.leftMargin - lp.rightMargin;
1618 break;
1619
1620 case Gravity.RIGHT:
1621 childLeft = childRight - childWidth - lp.rightMargin;
1622 break;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001623
1624 case Gravity.LEFT:
Romain Guy611cd3f2009-12-15 12:00:37 -08001625 default:
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001626 childLeft = paddingLeft + lp.leftMargin;
Romain Guy611cd3f2009-12-15 12:00:37 -08001627 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001628 }
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001629
Adam Powell696cba52011-03-29 10:38:16 -07001630 if (hasDividerBeforeChildAt(i)) {
1631 childTop += mDividerHeight;
1632 }
1633
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001634 childTop += lp.topMargin;
1635 setChildFrame(child, childLeft, childTop + getLocationOffset(child),
1636 childWidth, childHeight);
1637 childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);
1638
1639 i += getChildrenSkipCount(child, i);
1640 }
1641 }
1642 }
1643
Selim Cinek78528b22015-06-02 17:33:09 +02001644 @Override
1645 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) {
1646 super.onRtlPropertiesChanged(layoutDirection);
1647 if (layoutDirection != mLayoutDirection) {
1648 mLayoutDirection = layoutDirection;
1649 if (mOrientation == HORIZONTAL) {
1650 requestLayout();
1651 }
1652 }
1653 }
1654
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001655 /**
1656 * Position the children during a layout pass if the orientation of this
1657 * LinearLayout is set to {@link #HORIZONTAL}.
1658 *
1659 * @see #getOrientation()
1660 * @see #setOrientation(int)
1661 * @see #onLayout(boolean, int, int, int, int)
Philip Milnead365cc2012-09-27 14:38:46 -07001662 * @param left
1663 * @param top
1664 * @param right
1665 * @param bottom
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001666 */
Philip Milnead365cc2012-09-27 14:38:46 -07001667 void layoutHorizontal(int left, int top, int right, int bottom) {
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001668 final boolean isLayoutRtl = isLayoutRtl();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001669 final int paddingTop = mPaddingTop;
1670
Romain Guy5b1b2412010-01-21 19:09:51 -08001671 int childTop;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001672 int childLeft;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001673
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001674 // Where bottom of child should go
Philip Milnead365cc2012-09-27 14:38:46 -07001675 final int height = bottom - top;
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001676 int childBottom = height - mPaddingBottom;
1677
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001678 // Space available for child
1679 int childSpace = height - paddingTop - mPaddingBottom;
1680
1681 final int count = getVirtualChildCount();
1682
Fabrice Di Meglio6a036402011-05-23 14:43:23 -07001683 final int majorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001684 final int minorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
1685
1686 final boolean baselineAligned = mBaselineAligned;
1687
1688 final int[] maxAscent = mMaxAscent;
1689 final int[] maxDescent = mMaxDescent;
1690
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07001691 final int layoutDirection = getLayoutDirection();
Fabrice Di Meglioc0053222011-06-13 12:16:51 -07001692 switch (Gravity.getAbsoluteGravity(majorGravity, layoutDirection)) {
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001693 case Gravity.RIGHT:
1694 // mTotalLength contains the padding already
Philip Milnead365cc2012-09-27 14:38:46 -07001695 childLeft = mPaddingLeft + right - left - mTotalLength;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001696 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001697
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001698 case Gravity.CENTER_HORIZONTAL:
1699 // mTotalLength contains the padding already
Philip Milnead365cc2012-09-27 14:38:46 -07001700 childLeft = mPaddingLeft + (right - left - mTotalLength) / 2;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001701 break;
1702
1703 case Gravity.LEFT:
1704 default:
1705 childLeft = mPaddingLeft;
1706 break;
1707 }
1708
1709 int start = 0;
1710 int dir = 1;
1711 //In case of RTL, start drawing from the last child.
1712 if (isLayoutRtl) {
1713 start = count - 1;
1714 dir = -1;
Adam Powellfcca00a2010-11-30 21:26:29 -08001715 }
1716
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 for (int i = 0; i < count; i++) {
Alan Viverettead526932015-12-17 12:42:39 -05001718 final int childIndex = start + dir * i;
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001719 final View child = getVirtualChildAt(childIndex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001720 if (child == null) {
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001721 childLeft += measureNullChild(childIndex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001722 } else if (child.getVisibility() != GONE) {
1723 final int childWidth = child.getMeasuredWidth();
1724 final int childHeight = child.getMeasuredHeight();
1725 int childBaseline = -1;
1726
1727 final LinearLayout.LayoutParams lp =
1728 (LinearLayout.LayoutParams) child.getLayoutParams();
1729
Romain Guy980a9382010-01-08 15:06:28 -08001730 if (baselineAligned && lp.height != LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001731 childBaseline = child.getBaseline();
1732 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001733
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 int gravity = lp.gravity;
1735 if (gravity < 0) {
1736 gravity = minorGravity;
1737 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001738
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001739 switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
1740 case Gravity.TOP:
1741 childTop = paddingTop + lp.topMargin;
1742 if (childBaseline != -1) {
1743 childTop += maxAscent[INDEX_TOP] - childBaseline;
1744 }
1745 break;
1746
1747 case Gravity.CENTER_VERTICAL:
Romain Guy5b1b2412010-01-21 19:09:51 -08001748 // Removed support for baseline alignment when layout_gravity or
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001749 // gravity == center_vertical. See bug #1038483.
1750 // Keep the code around if we need to re-enable this feature
1751 // if (childBaseline != -1) {
1752 // // Align baselines vertically only if the child is smaller than us
1753 // if (childSpace - childHeight > 0) {
1754 // childTop = paddingTop + (childSpace / 2) - childBaseline;
1755 // } else {
1756 // childTop = paddingTop + (childSpace - childHeight) / 2;
1757 // }
1758 // } else {
1759 childTop = paddingTop + ((childSpace - childHeight) / 2)
1760 + lp.topMargin - lp.bottomMargin;
1761 break;
1762
1763 case Gravity.BOTTOM:
1764 childTop = childBottom - childHeight - lp.bottomMargin;
1765 if (childBaseline != -1) {
1766 int descent = child.getMeasuredHeight() - childBaseline;
1767 childTop -= (maxDescent[INDEX_BOTTOM] - descent);
1768 }
1769 break;
Romain Guy611cd3f2009-12-15 12:00:37 -08001770 default:
1771 childTop = paddingTop;
1772 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001773 }
1774
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001775 if (hasDividerBeforeChildAt(childIndex)) {
Adam Powell696cba52011-03-29 10:38:16 -07001776 childLeft += mDividerWidth;
1777 }
1778
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001779 childLeft += lp.leftMargin;
1780 setChildFrame(child, childLeft + getLocationOffset(child), childTop,
1781 childWidth, childHeight);
1782 childLeft += childWidth + lp.rightMargin +
1783 getNextLocationOffset(child);
1784
Fabrice Di Meglio1e4cfbe2010-04-01 15:46:27 -07001785 i += getChildrenSkipCount(child, childIndex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001786 }
1787 }
1788 }
1789
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001790 private void setChildFrame(View child, int left, int top, int width, int height) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001791 child.layout(left, top, left + width, top + height);
1792 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001793
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001794 /**
1795 * Should the layout be a column or a row.
Tor Norbyed9273d62013-05-30 15:59:53 -07001796 * @param orientation Pass {@link #HORIZONTAL} or {@link #VERTICAL}. Default
1797 * value is {@link #HORIZONTAL}.
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001798 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001799 * @attr ref android.R.styleable#LinearLayout_orientation
1800 */
Tor Norbyed9273d62013-05-30 15:59:53 -07001801 public void setOrientation(@OrientationMode int orientation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001802 if (mOrientation != orientation) {
1803 mOrientation = orientation;
1804 requestLayout();
1805 }
1806 }
1807
1808 /**
1809 * Returns the current orientation.
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001810 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001811 * @return either {@link #HORIZONTAL} or {@link #VERTICAL}
1812 */
Tor Norbyed9273d62013-05-30 15:59:53 -07001813 @OrientationMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 public int getOrientation() {
1815 return mOrientation;
1816 }
1817
1818 /**
1819 * Describes how the child views are positioned. Defaults to GRAVITY_TOP. If
1820 * this layout has a VERTICAL orientation, this controls where all the child
1821 * views are placed if there is extra vertical space. If this layout has a
1822 * HORIZONTAL orientation, this controls the alignment of the children.
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001823 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001824 * @param gravity See {@link android.view.Gravity}
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001825 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001826 * @attr ref android.R.styleable#LinearLayout_gravity
1827 */
1828 @android.view.RemotableViewMethod
1829 public void setGravity(int gravity) {
1830 if (mGravity != gravity) {
Fabrice Di Meglio6a036402011-05-23 14:43:23 -07001831 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
Fabrice Di Meglio9e3b0022011-06-06 16:30:29 -07001832 gravity |= Gravity.START;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001833 }
1834
1835 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
1836 gravity |= Gravity.TOP;
1837 }
1838
1839 mGravity = gravity;
1840 requestLayout();
1841 }
1842 }
1843
Jason Monkefe916c2016-01-20 10:46:12 -05001844 /**
1845 * Returns the current gravity. See {@link android.view.Gravity}
1846 *
1847 * @return the current gravity.
1848 * @see #setGravity
1849 */
1850 public int getGravity() {
1851 return mGravity;
1852 }
1853
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001854 @android.view.RemotableViewMethod
1855 public void setHorizontalGravity(int horizontalGravity) {
Fabrice Di Meglio6a036402011-05-23 14:43:23 -07001856 final int gravity = horizontalGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
1857 if ((mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) != gravity) {
1858 mGravity = (mGravity & ~Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) | gravity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001859 requestLayout();
1860 }
1861 }
1862
1863 @android.view.RemotableViewMethod
1864 public void setVerticalGravity(int verticalGravity) {
1865 final int gravity = verticalGravity & Gravity.VERTICAL_GRAVITY_MASK;
1866 if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != gravity) {
1867 mGravity = (mGravity & ~Gravity.VERTICAL_GRAVITY_MASK) | gravity;
1868 requestLayout();
1869 }
1870 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001871
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001872 @Override
1873 public LayoutParams generateLayoutParams(AttributeSet attrs) {
1874 return new LinearLayout.LayoutParams(getContext(), attrs);
1875 }
1876
1877 /**
1878 * Returns a set of layout parameters with a width of
Romain Guy980a9382010-01-08 15:06:28 -08001879 * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001880 * and a height of {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}
1881 * when the layout's orientation is {@link #VERTICAL}. When the orientation is
1882 * {@link #HORIZONTAL}, the width is set to {@link LayoutParams#WRAP_CONTENT}
1883 * and the height to {@link LayoutParams#WRAP_CONTENT}.
1884 */
1885 @Override
1886 protected LayoutParams generateDefaultLayoutParams() {
1887 if (mOrientation == HORIZONTAL) {
1888 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
1889 } else if (mOrientation == VERTICAL) {
Romain Guy980a9382010-01-08 15:06:28 -08001890 return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001891 }
1892 return null;
1893 }
1894
1895 @Override
Yigit Boyar885c50b2016-03-22 16:53:42 -07001896 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
Yigit Boyar2dd20a62016-08-01 17:42:28 -07001897 if (sPreserveMarginParamsInLayoutParamConversion) {
1898 if (lp instanceof LayoutParams) {
1899 return new LayoutParams((LayoutParams) lp);
1900 } else if (lp instanceof MarginLayoutParams) {
1901 return new LayoutParams((MarginLayoutParams) lp);
1902 }
Yigit Boyar885c50b2016-03-22 16:53:42 -07001903 }
Yigit Boyar2dd20a62016-08-01 17:42:28 -07001904 return new LayoutParams(lp);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001905 }
1906
1907
1908 // Override to allow type-checking of LayoutParams.
1909 @Override
1910 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
1911 return p instanceof LinearLayout.LayoutParams;
1912 }
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08001913
1914 @Override
Dianne Hackborna7bb6fb2015-02-03 18:13:40 -08001915 public CharSequence getAccessibilityClassName() {
1916 return LinearLayout.class.getName();
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08001917 }
1918
Siva Velusamy94a6d152015-05-05 15:07:00 -07001919 /** @hide */
1920 @Override
1921 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
1922 super.encodeProperties(encoder);
1923 encoder.addProperty("layout:baselineAligned", mBaselineAligned);
1924 encoder.addProperty("layout:baselineAlignedChildIndex", mBaselineAlignedChildIndex);
1925 encoder.addProperty("measurement:baselineChildTop", mBaselineChildTop);
1926 encoder.addProperty("measurement:orientation", mOrientation);
1927 encoder.addProperty("measurement:gravity", mGravity);
1928 encoder.addProperty("measurement:totalLength", mTotalLength);
1929 encoder.addProperty("layout:totalLength", mTotalLength);
1930 encoder.addProperty("layout:useLargestChild", mUseLargestChild);
1931 }
1932
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001933 /**
1934 * Per-child layout information associated with ViewLinearLayout.
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001935 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001936 * @attr ref android.R.styleable#LinearLayout_Layout_layout_weight
1937 * @attr ref android.R.styleable#LinearLayout_Layout_layout_gravity
1938 */
1939 public static class LayoutParams extends ViewGroup.MarginLayoutParams {
1940 /**
1941 * Indicates how much of the extra space in the LinearLayout will be
1942 * allocated to the view associated with these LayoutParams. Specify
1943 * 0 if the view should not be stretched. Otherwise the extra pixels
1944 * will be pro-rated among all views whose weight is greater than 0.
1945 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07001946 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001947 public float weight;
1948
1949 /**
1950 * Gravity for the view associated with these LayoutParams.
1951 *
1952 * @see android.view.Gravity
1953 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07001954 @ViewDebug.ExportedProperty(category = "layout", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001955 @ViewDebug.IntToString(from = -1, to = "NONE"),
1956 @ViewDebug.IntToString(from = Gravity.NO_GRAVITY, to = "NONE"),
1957 @ViewDebug.IntToString(from = Gravity.TOP, to = "TOP"),
1958 @ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"),
1959 @ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"),
1960 @ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"),
Chet Haase8b9ed442016-08-25 15:35:53 -07001961 @ViewDebug.IntToString(from = Gravity.START, to = "START"),
1962 @ViewDebug.IntToString(from = Gravity.END, to = "END"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001963 @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"),
1964 @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"),
1965 @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
1966 @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL, to = "FILL_HORIZONTAL"),
1967 @ViewDebug.IntToString(from = Gravity.CENTER, to = "CENTER"),
1968 @ViewDebug.IntToString(from = Gravity.FILL, to = "FILL")
1969 })
1970 public int gravity = -1;
1971
1972 /**
1973 * {@inheritDoc}
1974 */
1975 public LayoutParams(Context c, AttributeSet attrs) {
1976 super(c, attrs);
1977 TypedArray a =
1978 c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout_Layout);
1979
1980 weight = a.getFloat(com.android.internal.R.styleable.LinearLayout_Layout_layout_weight, 0);
1981 gravity = a.getInt(com.android.internal.R.styleable.LinearLayout_Layout_layout_gravity, -1);
1982
1983 a.recycle();
1984 }
1985
1986 /**
1987 * {@inheritDoc}
1988 */
1989 public LayoutParams(int width, int height) {
1990 super(width, height);
1991 weight = 0;
1992 }
1993
1994 /**
1995 * Creates a new set of layout parameters with the specified width, height
1996 * and weight.
1997 *
Romain Guy980a9382010-01-08 15:06:28 -08001998 * @param width the width, either {@link #MATCH_PARENT},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001999 * {@link #WRAP_CONTENT} or a fixed size in pixels
Romain Guy980a9382010-01-08 15:06:28 -08002000 * @param height the height, either {@link #MATCH_PARENT},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002001 * {@link #WRAP_CONTENT} or a fixed size in pixels
2002 * @param weight the weight
2003 */
2004 public LayoutParams(int width, int height, float weight) {
2005 super(width, height);
2006 this.weight = weight;
2007 }
2008
2009 /**
2010 * {@inheritDoc}
2011 */
2012 public LayoutParams(ViewGroup.LayoutParams p) {
2013 super(p);
2014 }
2015
2016 /**
2017 * {@inheritDoc}
2018 */
Alan Viverette0a0e1552013-08-07 13:24:09 -07002019 public LayoutParams(ViewGroup.MarginLayoutParams source) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002020 super(source);
2021 }
2022
Alan Viverette0a0e1552013-08-07 13:24:09 -07002023 /**
2024 * Copy constructor. Clones the width, height, margin values, weight,
2025 * and gravity of the source.
2026 *
2027 * @param source The layout params to copy from.
2028 */
2029 public LayoutParams(LayoutParams source) {
2030 super(source);
2031
2032 this.weight = source.weight;
2033 this.gravity = source.gravity;
2034 }
2035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002036 @Override
2037 public String debug(String output) {
2038 return output + "LinearLayout.LayoutParams={width=" + sizeToString(width) +
2039 ", height=" + sizeToString(height) + " weight=" + weight + "}";
2040 }
Siva Velusamy94a6d152015-05-05 15:07:00 -07002041
2042 /** @hide */
2043 @Override
2044 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
2045 super.encodeProperties(encoder);
2046
2047 encoder.addProperty("layout:weight", weight);
2048 encoder.addProperty("layout:gravity", gravity);
2049 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002050 }
2051}