LinearLayout.java revision 9df0846498b2be2e03c487d0dba73c1d7c20f39c
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.widget; 18 19import com.android.internal.R; 20 21import android.annotation.IntDef; 22import android.annotation.NonNull; 23import android.annotation.Nullable; 24import android.content.Context; 25import android.content.res.TypedArray; 26import android.graphics.Canvas; 27import android.graphics.drawable.Drawable; 28import android.os.Build; 29import android.util.AttributeSet; 30import android.view.Gravity; 31import android.view.View; 32import android.view.ViewDebug; 33import android.view.ViewGroup; 34import android.view.ViewHierarchyEncoder; 35import android.widget.RemoteViews.RemoteView; 36 37import java.lang.annotation.Retention; 38import java.lang.annotation.RetentionPolicy; 39 40 41/** 42 * A Layout that arranges its children in a single column or a single row. The direction of 43 * the row can be set by calling {@link #setOrientation(int) setOrientation()}. 44 * You can also specify gravity, which specifies the alignment of all the child elements by 45 * calling {@link #setGravity(int) setGravity()} or specify that specific children 46 * grow to fill up any remaining space in the layout by setting the <em>weight</em> member of 47 * {@link android.widget.LinearLayout.LayoutParams LinearLayout.LayoutParams}. 48 * The default orientation is horizontal. 49 * 50 * <p>See the <a href="{@docRoot}guide/topics/ui/layout/linear.html">Linear Layout</a> 51 * guide.</p> 52 * 53 * <p> 54 * Also see {@link LinearLayout.LayoutParams android.widget.LinearLayout.LayoutParams} 55 * for layout attributes </p> 56 * 57 * @attr ref android.R.styleable#LinearLayout_baselineAligned 58 * @attr ref android.R.styleable#LinearLayout_baselineAlignedChildIndex 59 * @attr ref android.R.styleable#LinearLayout_gravity 60 * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild 61 * @attr ref android.R.styleable#LinearLayout_orientation 62 * @attr ref android.R.styleable#LinearLayout_weightSum 63 */ 64@RemoteView 65public class LinearLayout extends ViewGroup { 66 /** @hide */ 67 @IntDef({HORIZONTAL, VERTICAL}) 68 @Retention(RetentionPolicy.SOURCE) 69 public @interface OrientationMode {} 70 71 public static final int HORIZONTAL = 0; 72 public static final int VERTICAL = 1; 73 74 /** @hide */ 75 @IntDef(flag = true, 76 value = { 77 SHOW_DIVIDER_NONE, 78 SHOW_DIVIDER_BEGINNING, 79 SHOW_DIVIDER_MIDDLE, 80 SHOW_DIVIDER_END 81 }) 82 @Retention(RetentionPolicy.SOURCE) 83 public @interface DividerMode {} 84 85 /** 86 * Don't show any dividers. 87 */ 88 public static final int SHOW_DIVIDER_NONE = 0; 89 /** 90 * Show a divider at the beginning of the group. 91 */ 92 public static final int SHOW_DIVIDER_BEGINNING = 1; 93 /** 94 * Show dividers between each item in the group. 95 */ 96 public static final int SHOW_DIVIDER_MIDDLE = 2; 97 /** 98 * Show a divider at the end of the group. 99 */ 100 public static final int SHOW_DIVIDER_END = 4; 101 102 /** 103 * Compatibility check. Old versions of the platform would give different 104 * results from measurement passes using EXACTLY and non-EXACTLY modes, 105 * even when the resulting size was the same. 106 */ 107 private final boolean mAllowInconsistentMeasurement; 108 109 /** 110 * Whether the children of this layout are baseline aligned. Only applicable 111 * if {@link #mOrientation} is horizontal. 112 */ 113 @ViewDebug.ExportedProperty(category = "layout") 114 private boolean mBaselineAligned = true; 115 116 /** 117 * If this layout is part of another layout that is baseline aligned, 118 * use the child at this index as the baseline. 119 * 120 * Note: this is orthogonal to {@link #mBaselineAligned}, which is concerned 121 * with whether the children of this layout are baseline aligned. 122 */ 123 @ViewDebug.ExportedProperty(category = "layout") 124 private int mBaselineAlignedChildIndex = -1; 125 126 /** 127 * The additional offset to the child's baseline. 128 * We'll calculate the baseline of this layout as we measure vertically; for 129 * horizontal linear layouts, the offset of 0 is appropriate. 130 */ 131 @ViewDebug.ExportedProperty(category = "measurement") 132 private int mBaselineChildTop = 0; 133 134 @ViewDebug.ExportedProperty(category = "measurement") 135 private int mOrientation; 136 137 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 138 @ViewDebug.FlagToString(mask = -1, 139 equals = -1, name = "NONE"), 140 @ViewDebug.FlagToString(mask = Gravity.NO_GRAVITY, 141 equals = Gravity.NO_GRAVITY,name = "NONE"), 142 @ViewDebug.FlagToString(mask = Gravity.TOP, 143 equals = Gravity.TOP, name = "TOP"), 144 @ViewDebug.FlagToString(mask = Gravity.BOTTOM, 145 equals = Gravity.BOTTOM, name = "BOTTOM"), 146 @ViewDebug.FlagToString(mask = Gravity.LEFT, 147 equals = Gravity.LEFT, name = "LEFT"), 148 @ViewDebug.FlagToString(mask = Gravity.RIGHT, 149 equals = Gravity.RIGHT, name = "RIGHT"), 150 @ViewDebug.FlagToString(mask = Gravity.START, 151 equals = Gravity.START, name = "START"), 152 @ViewDebug.FlagToString(mask = Gravity.END, 153 equals = Gravity.END, name = "END"), 154 @ViewDebug.FlagToString(mask = Gravity.CENTER_VERTICAL, 155 equals = Gravity.CENTER_VERTICAL, name = "CENTER_VERTICAL"), 156 @ViewDebug.FlagToString(mask = Gravity.FILL_VERTICAL, 157 equals = Gravity.FILL_VERTICAL, name = "FILL_VERTICAL"), 158 @ViewDebug.FlagToString(mask = Gravity.CENTER_HORIZONTAL, 159 equals = Gravity.CENTER_HORIZONTAL, name = "CENTER_HORIZONTAL"), 160 @ViewDebug.FlagToString(mask = Gravity.FILL_HORIZONTAL, 161 equals = Gravity.FILL_HORIZONTAL, name = "FILL_HORIZONTAL"), 162 @ViewDebug.FlagToString(mask = Gravity.CENTER, 163 equals = Gravity.CENTER, name = "CENTER"), 164 @ViewDebug.FlagToString(mask = Gravity.FILL, 165 equals = Gravity.FILL, name = "FILL"), 166 @ViewDebug.FlagToString(mask = Gravity.RELATIVE_LAYOUT_DIRECTION, 167 equals = Gravity.RELATIVE_LAYOUT_DIRECTION, name = "RELATIVE") 168 }, formatToHexString = true) 169 private int mGravity = Gravity.START | Gravity.TOP; 170 171 @ViewDebug.ExportedProperty(category = "measurement") 172 private int mTotalLength; 173 174 @ViewDebug.ExportedProperty(category = "layout") 175 private float mWeightSum; 176 177 @ViewDebug.ExportedProperty(category = "layout") 178 private boolean mUseLargestChild; 179 180 private int[] mMaxAscent; 181 private int[] mMaxDescent; 182 183 private static final int VERTICAL_GRAVITY_COUNT = 4; 184 185 private static final int INDEX_CENTER_VERTICAL = 0; 186 private static final int INDEX_TOP = 1; 187 private static final int INDEX_BOTTOM = 2; 188 private static final int INDEX_FILL = 3; 189 190 private Drawable mDivider; 191 private int mDividerWidth; 192 private int mDividerHeight; 193 private int mShowDividers; 194 private int mDividerPadding; 195 196 private int mLayoutDirection = View.LAYOUT_DIRECTION_UNDEFINED; 197 198 public LinearLayout(Context context) { 199 this(context, null); 200 } 201 202 public LinearLayout(Context context, @Nullable AttributeSet attrs) { 203 this(context, attrs, 0); 204 } 205 206 public LinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 207 this(context, attrs, defStyleAttr, 0); 208 } 209 210 public LinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 211 super(context, attrs, defStyleAttr, defStyleRes); 212 213 final TypedArray a = context.obtainStyledAttributes( 214 attrs, com.android.internal.R.styleable.LinearLayout, defStyleAttr, defStyleRes); 215 216 int index = a.getInt(com.android.internal.R.styleable.LinearLayout_orientation, -1); 217 if (index >= 0) { 218 setOrientation(index); 219 } 220 221 index = a.getInt(com.android.internal.R.styleable.LinearLayout_gravity, -1); 222 if (index >= 0) { 223 setGravity(index); 224 } 225 226 boolean baselineAligned = a.getBoolean(R.styleable.LinearLayout_baselineAligned, true); 227 if (!baselineAligned) { 228 setBaselineAligned(baselineAligned); 229 } 230 231 mWeightSum = a.getFloat(R.styleable.LinearLayout_weightSum, -1.0f); 232 233 mBaselineAlignedChildIndex = 234 a.getInt(com.android.internal.R.styleable.LinearLayout_baselineAlignedChildIndex, -1); 235 236 mUseLargestChild = a.getBoolean(R.styleable.LinearLayout_measureWithLargestChild, false); 237 238 setDividerDrawable(a.getDrawable(R.styleable.LinearLayout_divider)); 239 mShowDividers = a.getInt(R.styleable.LinearLayout_showDividers, SHOW_DIVIDER_NONE); 240 mDividerPadding = a.getDimensionPixelSize(R.styleable.LinearLayout_dividerPadding, 0); 241 242 final int version = context.getApplicationInfo().targetSdkVersion; 243 mAllowInconsistentMeasurement = version <= Build.VERSION_CODES.M; 244 245 a.recycle(); 246 } 247 248 /** 249 * Returns <code>true</code> if this layout is currently configured to show at least one 250 * divider. 251 */ 252 private boolean isShowingDividers() { 253 return (mShowDividers != SHOW_DIVIDER_NONE) && (mDivider != null); 254 } 255 256 /** 257 * Set how dividers should be shown between items in this layout 258 * 259 * @param showDividers One or more of {@link #SHOW_DIVIDER_BEGINNING}, 260 * {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END} 261 * to show dividers, or {@link #SHOW_DIVIDER_NONE} to show no dividers. 262 */ 263 public void setShowDividers(@DividerMode int showDividers) { 264 if (showDividers == mShowDividers) { 265 return; 266 } 267 mShowDividers = showDividers; 268 269 setWillNotDraw(!isShowingDividers()); 270 requestLayout(); 271 } 272 273 @Override 274 public boolean shouldDelayChildPressedState() { 275 return false; 276 } 277 278 /** 279 * @return A flag set indicating how dividers should be shown around items. 280 * @see #setShowDividers(int) 281 */ 282 @DividerMode 283 public int getShowDividers() { 284 return mShowDividers; 285 } 286 287 /** 288 * @return the divider Drawable that will divide each item. 289 * 290 * @see #setDividerDrawable(Drawable) 291 * 292 * @attr ref android.R.styleable#LinearLayout_divider 293 */ 294 public Drawable getDividerDrawable() { 295 return mDivider; 296 } 297 298 /** 299 * Set a drawable to be used as a divider between items. 300 * 301 * @param divider Drawable that will divide each item. 302 * 303 * @see #setShowDividers(int) 304 * 305 * @attr ref android.R.styleable#LinearLayout_divider 306 */ 307 public void setDividerDrawable(Drawable divider) { 308 if (divider == mDivider) { 309 return; 310 } 311 mDivider = divider; 312 if (divider != null) { 313 mDividerWidth = divider.getIntrinsicWidth(); 314 mDividerHeight = divider.getIntrinsicHeight(); 315 } else { 316 mDividerWidth = 0; 317 mDividerHeight = 0; 318 } 319 320 setWillNotDraw(!isShowingDividers()); 321 requestLayout(); 322 } 323 324 /** 325 * Set padding displayed on both ends of dividers. For a vertical layout, the padding is applied 326 * to left and right end of dividers. For a horizontal layout, the padding is applied to top and 327 * bottom end of dividers. 328 * 329 * @param padding Padding value in pixels that will be applied to each end 330 * 331 * @see #setShowDividers(int) 332 * @see #setDividerDrawable(Drawable) 333 * @see #getDividerPadding() 334 */ 335 public void setDividerPadding(int padding) { 336 if (padding == mDividerPadding) { 337 return; 338 } 339 mDividerPadding = padding; 340 341 if (isShowingDividers()) { 342 requestLayout(); 343 invalidate(); 344 } 345 } 346 347 /** 348 * Get the padding size used to inset dividers in pixels 349 * 350 * @see #setShowDividers(int) 351 * @see #setDividerDrawable(Drawable) 352 * @see #setDividerPadding(int) 353 */ 354 public int getDividerPadding() { 355 return mDividerPadding; 356 } 357 358 /** 359 * Get the width of the current divider drawable. 360 * 361 * @hide Used internally by framework. 362 */ 363 public int getDividerWidth() { 364 return mDividerWidth; 365 } 366 367 @Override 368 protected void onDraw(Canvas canvas) { 369 if (mDivider == null) { 370 return; 371 } 372 373 if (mOrientation == VERTICAL) { 374 drawDividersVertical(canvas); 375 } else { 376 drawDividersHorizontal(canvas); 377 } 378 } 379 380 void drawDividersVertical(Canvas canvas) { 381 final int count = getVirtualChildCount(); 382 for (int i = 0; i < count; i++) { 383 final View child = getVirtualChildAt(i); 384 if (child != null && child.getVisibility() != GONE) { 385 if (hasDividerBeforeChildAt(i)) { 386 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 387 final int top = child.getTop() - lp.topMargin - mDividerHeight; 388 drawHorizontalDivider(canvas, top); 389 } 390 } 391 } 392 393 if (hasDividerBeforeChildAt(count)) { 394 final View child = getLastNonGoneChild(); 395 int bottom = 0; 396 if (child == null) { 397 bottom = getHeight() - getPaddingBottom() - mDividerHeight; 398 } else { 399 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 400 bottom = child.getBottom() + lp.bottomMargin; 401 } 402 drawHorizontalDivider(canvas, bottom); 403 } 404 } 405 406 /** 407 * Finds the last child that is not gone. The last child will be used as the reference for 408 * where the end divider should be drawn. 409 */ 410 private View getLastNonGoneChild() { 411 for (int i = getVirtualChildCount() - 1; i >= 0; i--) { 412 final View child = getVirtualChildAt(i); 413 if (child != null && child.getVisibility() != GONE) { 414 return child; 415 } 416 } 417 return null; 418 } 419 420 void drawDividersHorizontal(Canvas canvas) { 421 final int count = getVirtualChildCount(); 422 final boolean isLayoutRtl = isLayoutRtl(); 423 for (int i = 0; i < count; i++) { 424 final View child = getVirtualChildAt(i); 425 if (child != null && child.getVisibility() != GONE) { 426 if (hasDividerBeforeChildAt(i)) { 427 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 428 final int position; 429 if (isLayoutRtl) { 430 position = child.getRight() + lp.rightMargin; 431 } else { 432 position = child.getLeft() - lp.leftMargin - mDividerWidth; 433 } 434 drawVerticalDivider(canvas, position); 435 } 436 } 437 } 438 439 if (hasDividerBeforeChildAt(count)) { 440 final View child = getLastNonGoneChild(); 441 int position; 442 if (child == null) { 443 if (isLayoutRtl) { 444 position = getPaddingLeft(); 445 } else { 446 position = getWidth() - getPaddingRight() - mDividerWidth; 447 } 448 } else { 449 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 450 if (isLayoutRtl) { 451 position = child.getLeft() - lp.leftMargin - mDividerWidth; 452 } else { 453 position = child.getRight() + lp.rightMargin; 454 } 455 } 456 drawVerticalDivider(canvas, position); 457 } 458 } 459 460 void drawHorizontalDivider(Canvas canvas, int top) { 461 mDivider.setBounds(getPaddingLeft() + mDividerPadding, top, 462 getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight); 463 mDivider.draw(canvas); 464 } 465 466 void drawVerticalDivider(Canvas canvas, int left) { 467 mDivider.setBounds(left, getPaddingTop() + mDividerPadding, 468 left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding); 469 mDivider.draw(canvas); 470 } 471 472 /** 473 * <p>Indicates whether widgets contained within this layout are aligned 474 * on their baseline or not.</p> 475 * 476 * @return true when widgets are baseline-aligned, false otherwise 477 */ 478 public boolean isBaselineAligned() { 479 return mBaselineAligned; 480 } 481 482 /** 483 * <p>Defines whether widgets contained in this layout are 484 * baseline-aligned or not.</p> 485 * 486 * @param baselineAligned true to align widgets on their baseline, 487 * false otherwise 488 * 489 * @attr ref android.R.styleable#LinearLayout_baselineAligned 490 */ 491 @android.view.RemotableViewMethod 492 public void setBaselineAligned(boolean baselineAligned) { 493 mBaselineAligned = baselineAligned; 494 } 495 496 /** 497 * When true, all children with a weight will be considered having 498 * the minimum size of the largest child. If false, all children are 499 * measured normally. 500 * 501 * @return True to measure children with a weight using the minimum 502 * size of the largest child, false otherwise. 503 * 504 * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild 505 */ 506 public boolean isMeasureWithLargestChildEnabled() { 507 return mUseLargestChild; 508 } 509 510 /** 511 * When set to true, all children with a weight will be considered having 512 * the minimum size of the largest child. If false, all children are 513 * measured normally. 514 * 515 * Disabled by default. 516 * 517 * @param enabled True to measure children with a weight using the 518 * minimum size of the largest child, false otherwise. 519 * 520 * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild 521 */ 522 @android.view.RemotableViewMethod 523 public void setMeasureWithLargestChildEnabled(boolean enabled) { 524 mUseLargestChild = enabled; 525 } 526 527 @Override 528 public int getBaseline() { 529 if (mBaselineAlignedChildIndex < 0) { 530 return super.getBaseline(); 531 } 532 533 if (getChildCount() <= mBaselineAlignedChildIndex) { 534 throw new RuntimeException("mBaselineAlignedChildIndex of LinearLayout " 535 + "set to an index that is out of bounds."); 536 } 537 538 final View child = getChildAt(mBaselineAlignedChildIndex); 539 final int childBaseline = child.getBaseline(); 540 541 if (childBaseline == -1) { 542 if (mBaselineAlignedChildIndex == 0) { 543 // this is just the default case, safe to return -1 544 return -1; 545 } 546 // the user picked an index that points to something that doesn't 547 // know how to calculate its baseline. 548 throw new RuntimeException("mBaselineAlignedChildIndex of LinearLayout " 549 + "points to a View that doesn't know how to get its baseline."); 550 } 551 552 // TODO: This should try to take into account the virtual offsets 553 // (See getNextLocationOffset and getLocationOffset) 554 // We should add to childTop: 555 // sum([getNextLocationOffset(getChildAt(i)) / i < mBaselineAlignedChildIndex]) 556 // and also add: 557 // getLocationOffset(child) 558 int childTop = mBaselineChildTop; 559 560 if (mOrientation == VERTICAL) { 561 final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK; 562 if (majorGravity != Gravity.TOP) { 563 switch (majorGravity) { 564 case Gravity.BOTTOM: 565 childTop = mBottom - mTop - mPaddingBottom - mTotalLength; 566 break; 567 568 case Gravity.CENTER_VERTICAL: 569 childTop += ((mBottom - mTop - mPaddingTop - mPaddingBottom) - 570 mTotalLength) / 2; 571 break; 572 } 573 } 574 } 575 576 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams(); 577 return childTop + lp.topMargin + childBaseline; 578 } 579 580 /** 581 * @return The index of the child that will be used if this layout is 582 * part of a larger layout that is baseline aligned, or -1 if none has 583 * been set. 584 */ 585 public int getBaselineAlignedChildIndex() { 586 return mBaselineAlignedChildIndex; 587 } 588 589 /** 590 * @param i The index of the child that will be used if this layout is 591 * part of a larger layout that is baseline aligned. 592 * 593 * @attr ref android.R.styleable#LinearLayout_baselineAlignedChildIndex 594 */ 595 @android.view.RemotableViewMethod 596 public void setBaselineAlignedChildIndex(int i) { 597 if ((i < 0) || (i >= getChildCount())) { 598 throw new IllegalArgumentException("base aligned child index out " 599 + "of range (0, " + getChildCount() + ")"); 600 } 601 mBaselineAlignedChildIndex = i; 602 } 603 604 /** 605 * <p>Returns the view at the specified index. This method can be overriden 606 * to take into account virtual children. Refer to 607 * {@link android.widget.TableLayout} and {@link android.widget.TableRow} 608 * for an example.</p> 609 * 610 * @param index the child's index 611 * @return the child at the specified index, may be {@code null} 612 */ 613 @Nullable 614 View getVirtualChildAt(int index) { 615 return getChildAt(index); 616 } 617 618 /** 619 * <p>Returns the virtual number of children. This number might be different 620 * than the actual number of children if the layout can hold virtual 621 * children. Refer to 622 * {@link android.widget.TableLayout} and {@link android.widget.TableRow} 623 * for an example.</p> 624 * 625 * @return the virtual number of children 626 */ 627 int getVirtualChildCount() { 628 return getChildCount(); 629 } 630 631 /** 632 * Returns the desired weights sum. 633 * 634 * @return A number greater than 0.0f if the weight sum is defined, or 635 * a number lower than or equals to 0.0f if not weight sum is 636 * to be used. 637 */ 638 public float getWeightSum() { 639 return mWeightSum; 640 } 641 642 /** 643 * Defines the desired weights sum. If unspecified the weights sum is computed 644 * at layout time by adding the layout_weight of each child. 645 * 646 * This can be used for instance to give a single child 50% of the total 647 * available space by giving it a layout_weight of 0.5 and setting the 648 * weightSum to 1.0. 649 * 650 * @param weightSum a number greater than 0.0f, or a number lower than or equals 651 * to 0.0f if the weight sum should be computed from the children's 652 * layout_weight 653 */ 654 @android.view.RemotableViewMethod 655 public void setWeightSum(float weightSum) { 656 mWeightSum = Math.max(0.0f, weightSum); 657 } 658 659 @Override 660 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 661 if (mOrientation == VERTICAL) { 662 measureVertical(widthMeasureSpec, heightMeasureSpec); 663 } else { 664 measureHorizontal(widthMeasureSpec, heightMeasureSpec); 665 } 666 } 667 668 /** 669 * Determines where to position dividers between children. 670 * 671 * @param childIndex Index of child to check for preceding divider 672 * @return true if there should be a divider before the child at childIndex 673 * @hide Pending API consideration. Currently only used internally by the system. 674 */ 675 protected boolean hasDividerBeforeChildAt(int childIndex) { 676 if (childIndex == getVirtualChildCount()) { 677 // Check whether the end divider should draw. 678 return (mShowDividers & SHOW_DIVIDER_END) != 0; 679 } 680 boolean allViewsAreGoneBefore = allViewsAreGoneBefore(childIndex); 681 if (allViewsAreGoneBefore) { 682 // This is the first view that's not gone, check if beginning divider is enabled. 683 return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0; 684 } else { 685 return (mShowDividers & SHOW_DIVIDER_MIDDLE) != 0; 686 } 687 } 688 689 /** 690 * Checks whether all (virtual) child views before the given index are gone. 691 */ 692 private boolean allViewsAreGoneBefore(int childIndex) { 693 for (int i = childIndex - 1; i >= 0; i--) { 694 final View child = getVirtualChildAt(i); 695 if (child != null && child.getVisibility() != GONE) { 696 return false; 697 } 698 } 699 return true; 700 } 701 702 /** 703 * Measures the children when the orientation of this LinearLayout is set 704 * to {@link #VERTICAL}. 705 * 706 * @param widthMeasureSpec Horizontal space requirements as imposed by the parent. 707 * @param heightMeasureSpec Vertical space requirements as imposed by the parent. 708 * 709 * @see #getOrientation() 710 * @see #setOrientation(int) 711 * @see #onMeasure(int, int) 712 */ 713 void measureVertical(int widthMeasureSpec, int heightMeasureSpec) { 714 mTotalLength = 0; 715 int maxWidth = 0; 716 int childState = 0; 717 int alternativeMaxWidth = 0; 718 int weightedMaxWidth = 0; 719 boolean allFillParent = true; 720 float totalWeight = 0; 721 722 final int count = getVirtualChildCount(); 723 724 final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 725 final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 726 727 boolean matchWidth = false; 728 boolean skippedMeasure = false; 729 730 final int baselineChildIndex = mBaselineAlignedChildIndex; 731 final boolean useLargestChild = mUseLargestChild; 732 733 int largestChildHeight = Integer.MIN_VALUE; 734 int consumedExcessSpace = 0; 735 736 int nonSkippedChildCount = 0; 737 738 // See how tall everyone is. Also remember max width. 739 for (int i = 0; i < count; ++i) { 740 final View child = getVirtualChildAt(i); 741 if (child == null) { 742 mTotalLength += measureNullChild(i); 743 continue; 744 } 745 746 if (child.getVisibility() == View.GONE) { 747 i += getChildrenSkipCount(child, i); 748 continue; 749 } 750 751 nonSkippedChildCount++; 752 if (hasDividerBeforeChildAt(i)) { 753 mTotalLength += mDividerHeight; 754 } 755 756 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 757 758 totalWeight += lp.weight; 759 760 final boolean useExcessSpace = lp.height == 0 && lp.weight > 0; 761 if (heightMode == MeasureSpec.EXACTLY && useExcessSpace) { 762 // Optimization: don't bother measuring children who are only 763 // laid out using excess space. These views will get measured 764 // later if we have space to distribute. 765 final int totalLength = mTotalLength; 766 mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin); 767 skippedMeasure = true; 768 } else { 769 if (useExcessSpace) { 770 // The heightMode is either UNSPECIFIED or AT_MOST, and 771 // this child is only laid out using excess space. Measure 772 // using WRAP_CONTENT so that we can find out the view's 773 // optimal height. We'll restore the original height of 0 774 // after measurement. 775 lp.height = LayoutParams.WRAP_CONTENT; 776 } 777 778 // Determine how big this child would like to be. If this or 779 // previous children have given a weight, then we allow it to 780 // use all available space (and we will shrink things later 781 // if needed). 782 final int usedHeight = totalWeight == 0 ? mTotalLength : 0; 783 measureChildBeforeLayout(child, i, widthMeasureSpec, 0, 784 heightMeasureSpec, usedHeight); 785 786 final int childHeight = child.getMeasuredHeight(); 787 if (useExcessSpace) { 788 // Restore the original height and record how much space 789 // we've allocated to excess-only children so that we can 790 // match the behavior of EXACTLY measurement. 791 lp.height = 0; 792 consumedExcessSpace += childHeight; 793 } 794 795 final int totalLength = mTotalLength; 796 mTotalLength = Math.max(totalLength, totalLength + childHeight + lp.topMargin + 797 lp.bottomMargin + getNextLocationOffset(child)); 798 799 if (useLargestChild) { 800 largestChildHeight = Math.max(childHeight, largestChildHeight); 801 } 802 } 803 804 /** 805 * If applicable, compute the additional offset to the child's baseline 806 * we'll need later when asked {@link #getBaseline}. 807 */ 808 if ((baselineChildIndex >= 0) && (baselineChildIndex == i + 1)) { 809 mBaselineChildTop = mTotalLength; 810 } 811 812 // if we are trying to use a child index for our baseline, the above 813 // book keeping only works if there are no children above it with 814 // weight. fail fast to aid the developer. 815 if (i < baselineChildIndex && lp.weight > 0) { 816 throw new RuntimeException("A child of LinearLayout with index " 817 + "less than mBaselineAlignedChildIndex has weight > 0, which " 818 + "won't work. Either remove the weight, or don't set " 819 + "mBaselineAlignedChildIndex."); 820 } 821 822 boolean matchWidthLocally = false; 823 if (widthMode != MeasureSpec.EXACTLY && lp.width == LayoutParams.MATCH_PARENT) { 824 // The width of the linear layout will scale, and at least one 825 // child said it wanted to match our width. Set a flag 826 // indicating that we need to remeasure at least that view when 827 // we know our width. 828 matchWidth = true; 829 matchWidthLocally = true; 830 } 831 832 final int margin = lp.leftMargin + lp.rightMargin; 833 final int measuredWidth = child.getMeasuredWidth() + margin; 834 maxWidth = Math.max(maxWidth, measuredWidth); 835 childState = combineMeasuredStates(childState, child.getMeasuredState()); 836 837 allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT; 838 if (lp.weight > 0) { 839 /* 840 * Widths of weighted Views are bogus if we end up 841 * remeasuring, so keep them separate. 842 */ 843 weightedMaxWidth = Math.max(weightedMaxWidth, 844 matchWidthLocally ? margin : measuredWidth); 845 } else { 846 alternativeMaxWidth = Math.max(alternativeMaxWidth, 847 matchWidthLocally ? margin : measuredWidth); 848 } 849 850 i += getChildrenSkipCount(child, i); 851 } 852 853 if (nonSkippedChildCount > 0 && hasDividerBeforeChildAt(count)) { 854 mTotalLength += mDividerHeight; 855 } 856 857 if (useLargestChild && 858 (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED)) { 859 mTotalLength = 0; 860 861 for (int i = 0; i < count; ++i) { 862 final View child = getVirtualChildAt(i); 863 if (child == null) { 864 mTotalLength += measureNullChild(i); 865 continue; 866 } 867 868 if (child.getVisibility() == GONE) { 869 i += getChildrenSkipCount(child, i); 870 continue; 871 } 872 873 final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) 874 child.getLayoutParams(); 875 // Account for negative margins 876 final int totalLength = mTotalLength; 877 mTotalLength = Math.max(totalLength, totalLength + largestChildHeight + 878 lp.topMargin + lp.bottomMargin + getNextLocationOffset(child)); 879 } 880 } 881 882 // Add in our padding 883 mTotalLength += mPaddingTop + mPaddingBottom; 884 885 int heightSize = mTotalLength; 886 887 // Check against our minimum height 888 heightSize = Math.max(heightSize, getSuggestedMinimumHeight()); 889 890 // Reconcile our calculated size with the heightMeasureSpec 891 int heightSizeAndState = resolveSizeAndState(heightSize, heightMeasureSpec, 0); 892 heightSize = heightSizeAndState & MEASURED_SIZE_MASK; 893 // Either expand children with weight to take up available space or 894 // shrink them if they extend beyond our current bounds. If we skipped 895 // measurement on any children, we need to measure them now. 896 int remainingExcess = heightSize - mTotalLength 897 + (mAllowInconsistentMeasurement ? 0 : consumedExcessSpace); 898 if (skippedMeasure || remainingExcess != 0 && totalWeight > 0.0f) { 899 float remainingWeightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight; 900 901 mTotalLength = 0; 902 903 for (int i = 0; i < count; ++i) { 904 final View child = getVirtualChildAt(i); 905 if (child == null || child.getVisibility() == View.GONE) { 906 continue; 907 } 908 909 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 910 final float childWeight = lp.weight; 911 if (childWeight > 0) { 912 final int share = (int) (childWeight * remainingExcess / remainingWeightSum); 913 remainingExcess -= share; 914 remainingWeightSum -= childWeight; 915 916 final int childHeight; 917 if (lp.height == 0 && (!mAllowInconsistentMeasurement 918 || heightMode == MeasureSpec.EXACTLY)) { 919 // This child needs to be laid out from scratch using 920 // only its share of excess space. 921 childHeight = share; 922 } else { 923 // This child had some intrinsic height to which we 924 // need to add its share of excess space. 925 childHeight = child.getMeasuredHeight() + share; 926 } 927 928 final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( 929 Math.max(0, childHeight), MeasureSpec.EXACTLY); 930 final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 931 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin, 932 lp.width); 933 child.measure(childWidthMeasureSpec, childHeightMeasureSpec); 934 935 // Child may now not fit in vertical dimension. 936 childState = combineMeasuredStates(childState, child.getMeasuredState() 937 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 938 } 939 940 final int margin = lp.leftMargin + lp.rightMargin; 941 final int measuredWidth = child.getMeasuredWidth() + margin; 942 maxWidth = Math.max(maxWidth, measuredWidth); 943 944 boolean matchWidthLocally = widthMode != MeasureSpec.EXACTLY && 945 lp.width == LayoutParams.MATCH_PARENT; 946 947 alternativeMaxWidth = Math.max(alternativeMaxWidth, 948 matchWidthLocally ? margin : measuredWidth); 949 950 allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT; 951 952 final int totalLength = mTotalLength; 953 mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredHeight() + 954 lp.topMargin + lp.bottomMargin + getNextLocationOffset(child)); 955 } 956 957 // Add in our padding 958 mTotalLength += mPaddingTop + mPaddingBottom; 959 // TODO: Should we recompute the heightSpec based on the new total length? 960 } else { 961 alternativeMaxWidth = Math.max(alternativeMaxWidth, 962 weightedMaxWidth); 963 964 965 // We have no limit, so make all weighted views as tall as the largest child. 966 // Children will have already been measured once. 967 if (useLargestChild && heightMode != MeasureSpec.EXACTLY) { 968 for (int i = 0; i < count; i++) { 969 final View child = getVirtualChildAt(i); 970 if (child == null || child.getVisibility() == View.GONE) { 971 continue; 972 } 973 974 final LinearLayout.LayoutParams lp = 975 (LinearLayout.LayoutParams) child.getLayoutParams(); 976 977 float childExtra = lp.weight; 978 if (childExtra > 0) { 979 child.measure( 980 MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(), 981 MeasureSpec.EXACTLY), 982 MeasureSpec.makeMeasureSpec(largestChildHeight, 983 MeasureSpec.EXACTLY)); 984 } 985 } 986 } 987 } 988 989 if (!allFillParent && widthMode != MeasureSpec.EXACTLY) { 990 maxWidth = alternativeMaxWidth; 991 } 992 993 maxWidth += mPaddingLeft + mPaddingRight; 994 995 // Check against our minimum width 996 maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth()); 997 998 setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState), 999 heightSizeAndState); 1000 1001 if (matchWidth) { 1002 forceUniformWidth(count, heightMeasureSpec); 1003 } 1004 } 1005 1006 private void forceUniformWidth(int count, int heightMeasureSpec) { 1007 // Pretend that the linear layout has an exact size. 1008 int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), 1009 MeasureSpec.EXACTLY); 1010 for (int i = 0; i< count; ++i) { 1011 final View child = getVirtualChildAt(i); 1012 if (child != null && child.getVisibility() != GONE) { 1013 LinearLayout.LayoutParams lp = ((LinearLayout.LayoutParams)child.getLayoutParams()); 1014 1015 if (lp.width == LayoutParams.MATCH_PARENT) { 1016 // Temporarily force children to reuse their old measured height 1017 // FIXME: this may not be right for something like wrapping text? 1018 int oldHeight = lp.height; 1019 lp.height = child.getMeasuredHeight(); 1020 1021 // Remeasue with new dimensions 1022 measureChildWithMargins(child, uniformMeasureSpec, 0, heightMeasureSpec, 0); 1023 lp.height = oldHeight; 1024 } 1025 } 1026 } 1027 } 1028 1029 /** 1030 * Measures the children when the orientation of this LinearLayout is set 1031 * to {@link #HORIZONTAL}. 1032 * 1033 * @param widthMeasureSpec Horizontal space requirements as imposed by the parent. 1034 * @param heightMeasureSpec Vertical space requirements as imposed by the parent. 1035 * 1036 * @see #getOrientation() 1037 * @see #setOrientation(int) 1038 * @see #onMeasure(int, int) 1039 */ 1040 void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec) { 1041 mTotalLength = 0; 1042 int maxHeight = 0; 1043 int childState = 0; 1044 int alternativeMaxHeight = 0; 1045 int weightedMaxHeight = 0; 1046 boolean allFillParent = true; 1047 float totalWeight = 0; 1048 1049 final int count = getVirtualChildCount(); 1050 1051 final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 1052 final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 1053 1054 boolean matchHeight = false; 1055 boolean skippedMeasure = false; 1056 1057 if (mMaxAscent == null || mMaxDescent == null) { 1058 mMaxAscent = new int[VERTICAL_GRAVITY_COUNT]; 1059 mMaxDescent = new int[VERTICAL_GRAVITY_COUNT]; 1060 } 1061 1062 final int[] maxAscent = mMaxAscent; 1063 final int[] maxDescent = mMaxDescent; 1064 1065 maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1; 1066 maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1; 1067 1068 final boolean baselineAligned = mBaselineAligned; 1069 final boolean useLargestChild = mUseLargestChild; 1070 1071 final boolean isExactly = widthMode == MeasureSpec.EXACTLY; 1072 1073 int largestChildWidth = Integer.MIN_VALUE; 1074 int usedExcessSpace = 0; 1075 1076 int nonSkippedChildCount = 0; 1077 1078 // See how wide everyone is. Also remember max height. 1079 for (int i = 0; i < count; ++i) { 1080 final View child = getVirtualChildAt(i); 1081 if (child == null) { 1082 mTotalLength += measureNullChild(i); 1083 continue; 1084 } 1085 1086 if (child.getVisibility() == GONE) { 1087 i += getChildrenSkipCount(child, i); 1088 continue; 1089 } 1090 1091 nonSkippedChildCount++; 1092 if (hasDividerBeforeChildAt(i)) { 1093 mTotalLength += mDividerWidth; 1094 } 1095 1096 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 1097 1098 totalWeight += lp.weight; 1099 1100 final boolean useExcessSpace = lp.width == 0 && lp.weight > 0; 1101 if (widthMode == MeasureSpec.EXACTLY && useExcessSpace) { 1102 // Optimization: don't bother measuring children who are only 1103 // laid out using excess space. These views will get measured 1104 // later if we have space to distribute. 1105 if (isExactly) { 1106 mTotalLength += lp.leftMargin + lp.rightMargin; 1107 } else { 1108 final int totalLength = mTotalLength; 1109 mTotalLength = Math.max(totalLength, totalLength + 1110 lp.leftMargin + lp.rightMargin); 1111 } 1112 1113 // Baseline alignment requires to measure widgets to obtain the 1114 // baseline offset (in particular for TextViews). The following 1115 // defeats the optimization mentioned above. Allow the child to 1116 // use as much space as it wants because we can shrink things 1117 // later (and re-measure). 1118 if (baselineAligned) { 1119 final int freeWidthSpec = MeasureSpec.makeSafeMeasureSpec( 1120 MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.UNSPECIFIED); 1121 final int freeHeightSpec = MeasureSpec.makeSafeMeasureSpec( 1122 MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED); 1123 child.measure(freeWidthSpec, freeHeightSpec); 1124 } else { 1125 skippedMeasure = true; 1126 } 1127 } else { 1128 if (useExcessSpace) { 1129 // The widthMode is either UNSPECIFIED or AT_MOST, and 1130 // this child is only laid out using excess space. Measure 1131 // using WRAP_CONTENT so that we can find out the view's 1132 // optimal width. We'll restore the original width of 0 1133 // after measurement. 1134 lp.width = LayoutParams.WRAP_CONTENT; 1135 } 1136 1137 // Determine how big this child would like to be. If this or 1138 // previous children have given a weight, then we allow it to 1139 // use all available space (and we will shrink things later 1140 // if needed). 1141 final int usedWidth = totalWeight == 0 ? mTotalLength : 0; 1142 measureChildBeforeLayout(child, i, widthMeasureSpec, usedWidth, 1143 heightMeasureSpec, 0); 1144 1145 final int childWidth = child.getMeasuredWidth(); 1146 if (useExcessSpace) { 1147 // Restore the original width and record how much space 1148 // we've allocated to excess-only children so that we can 1149 // match the behavior of EXACTLY measurement. 1150 lp.width = 0; 1151 usedExcessSpace += childWidth; 1152 } 1153 1154 if (isExactly) { 1155 mTotalLength += childWidth + lp.leftMargin + lp.rightMargin 1156 + getNextLocationOffset(child); 1157 } else { 1158 final int totalLength = mTotalLength; 1159 mTotalLength = Math.max(totalLength, totalLength + childWidth + lp.leftMargin 1160 + lp.rightMargin + getNextLocationOffset(child)); 1161 } 1162 1163 if (useLargestChild) { 1164 largestChildWidth = Math.max(childWidth, largestChildWidth); 1165 } 1166 } 1167 1168 boolean matchHeightLocally = false; 1169 if (heightMode != MeasureSpec.EXACTLY && lp.height == LayoutParams.MATCH_PARENT) { 1170 // The height of the linear layout will scale, and at least one 1171 // child said it wanted to match our height. Set a flag indicating that 1172 // we need to remeasure at least that view when we know our height. 1173 matchHeight = true; 1174 matchHeightLocally = true; 1175 } 1176 1177 final int margin = lp.topMargin + lp.bottomMargin; 1178 final int childHeight = child.getMeasuredHeight() + margin; 1179 childState = combineMeasuredStates(childState, child.getMeasuredState()); 1180 1181 if (baselineAligned) { 1182 final int childBaseline = child.getBaseline(); 1183 if (childBaseline != -1) { 1184 // Translates the child's vertical gravity into an index 1185 // in the range 0..VERTICAL_GRAVITY_COUNT 1186 final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity) 1187 & Gravity.VERTICAL_GRAVITY_MASK; 1188 final int index = ((gravity >> Gravity.AXIS_Y_SHIFT) 1189 & ~Gravity.AXIS_SPECIFIED) >> 1; 1190 1191 maxAscent[index] = Math.max(maxAscent[index], childBaseline); 1192 maxDescent[index] = Math.max(maxDescent[index], childHeight - childBaseline); 1193 } 1194 } 1195 1196 maxHeight = Math.max(maxHeight, childHeight); 1197 1198 allFillParent = allFillParent && lp.height == LayoutParams.MATCH_PARENT; 1199 if (lp.weight > 0) { 1200 /* 1201 * Heights of weighted Views are bogus if we end up 1202 * remeasuring, so keep them separate. 1203 */ 1204 weightedMaxHeight = Math.max(weightedMaxHeight, 1205 matchHeightLocally ? margin : childHeight); 1206 } else { 1207 alternativeMaxHeight = Math.max(alternativeMaxHeight, 1208 matchHeightLocally ? margin : childHeight); 1209 } 1210 1211 i += getChildrenSkipCount(child, i); 1212 } 1213 1214 if (nonSkippedChildCount > 0 && hasDividerBeforeChildAt(count)) { 1215 mTotalLength += mDividerWidth; 1216 } 1217 1218 // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP, 1219 // the most common case 1220 if (maxAscent[INDEX_TOP] != -1 || 1221 maxAscent[INDEX_CENTER_VERTICAL] != -1 || 1222 maxAscent[INDEX_BOTTOM] != -1 || 1223 maxAscent[INDEX_FILL] != -1) { 1224 final int ascent = Math.max(maxAscent[INDEX_FILL], 1225 Math.max(maxAscent[INDEX_CENTER_VERTICAL], 1226 Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM]))); 1227 final int descent = Math.max(maxDescent[INDEX_FILL], 1228 Math.max(maxDescent[INDEX_CENTER_VERTICAL], 1229 Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM]))); 1230 maxHeight = Math.max(maxHeight, ascent + descent); 1231 } 1232 1233 if (useLargestChild && 1234 (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.UNSPECIFIED)) { 1235 mTotalLength = 0; 1236 1237 for (int i = 0; i < count; ++i) { 1238 final View child = getVirtualChildAt(i); 1239 if (child == null) { 1240 mTotalLength += measureNullChild(i); 1241 continue; 1242 } 1243 1244 if (child.getVisibility() == GONE) { 1245 i += getChildrenSkipCount(child, i); 1246 continue; 1247 } 1248 1249 final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) 1250 child.getLayoutParams(); 1251 if (isExactly) { 1252 mTotalLength += largestChildWidth + lp.leftMargin + lp.rightMargin + 1253 getNextLocationOffset(child); 1254 } else { 1255 final int totalLength = mTotalLength; 1256 mTotalLength = Math.max(totalLength, totalLength + largestChildWidth + 1257 lp.leftMargin + lp.rightMargin + getNextLocationOffset(child)); 1258 } 1259 } 1260 } 1261 1262 // Add in our padding 1263 mTotalLength += mPaddingLeft + mPaddingRight; 1264 1265 int widthSize = mTotalLength; 1266 1267 // Check against our minimum width 1268 widthSize = Math.max(widthSize, getSuggestedMinimumWidth()); 1269 1270 // Reconcile our calculated size with the widthMeasureSpec 1271 int widthSizeAndState = resolveSizeAndState(widthSize, widthMeasureSpec, 0); 1272 widthSize = widthSizeAndState & MEASURED_SIZE_MASK; 1273 1274 // Either expand children with weight to take up available space or 1275 // shrink them if they extend beyond our current bounds. If we skipped 1276 // measurement on any children, we need to measure them now. 1277 int remainingExcess = widthSize - mTotalLength 1278 + (mAllowInconsistentMeasurement ? 0 : usedExcessSpace); 1279 if (skippedMeasure || remainingExcess != 0 && totalWeight > 0.0f) { 1280 float remainingWeightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight; 1281 1282 maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1; 1283 maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1; 1284 maxHeight = -1; 1285 1286 mTotalLength = 0; 1287 1288 for (int i = 0; i < count; ++i) { 1289 final View child = getVirtualChildAt(i); 1290 if (child == null || child.getVisibility() == View.GONE) { 1291 continue; 1292 } 1293 1294 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 1295 final float childWeight = lp.weight; 1296 if (childWeight > 0) { 1297 final int share = (int) (childWeight * remainingExcess / remainingWeightSum); 1298 remainingExcess -= share; 1299 remainingWeightSum -= childWeight; 1300 1301 final int childWidth; 1302 if (lp.width == 0 && (!mAllowInconsistentMeasurement 1303 || widthMode == MeasureSpec.EXACTLY)) { 1304 // This child needs to be laid out from scratch using 1305 // only its share of excess space. 1306 childWidth = share; 1307 } else { 1308 // This child had some intrinsic width to which we 1309 // need to add its share of excess space. 1310 childWidth = child.getMeasuredWidth() + share; 1311 } 1312 1313 final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec( 1314 Math.max(0, childWidth), MeasureSpec.EXACTLY); 1315 final int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, 1316 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin, 1317 lp.height); 1318 child.measure(childWidthMeasureSpec, childHeightMeasureSpec); 1319 1320 // Child may now not fit in horizontal dimension. 1321 childState = combineMeasuredStates(childState, 1322 child.getMeasuredState() & MEASURED_STATE_MASK); 1323 } 1324 1325 if (isExactly) { 1326 mTotalLength += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin + 1327 getNextLocationOffset(child); 1328 } else { 1329 final int totalLength = mTotalLength; 1330 mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredWidth() + 1331 lp.leftMargin + lp.rightMargin + getNextLocationOffset(child)); 1332 } 1333 1334 boolean matchHeightLocally = heightMode != MeasureSpec.EXACTLY && 1335 lp.height == LayoutParams.MATCH_PARENT; 1336 1337 final int margin = lp.topMargin + lp .bottomMargin; 1338 int childHeight = child.getMeasuredHeight() + margin; 1339 maxHeight = Math.max(maxHeight, childHeight); 1340 alternativeMaxHeight = Math.max(alternativeMaxHeight, 1341 matchHeightLocally ? margin : childHeight); 1342 1343 allFillParent = allFillParent && lp.height == LayoutParams.MATCH_PARENT; 1344 1345 if (baselineAligned) { 1346 final int childBaseline = child.getBaseline(); 1347 if (childBaseline != -1) { 1348 // Translates the child's vertical gravity into an index in the range 0..2 1349 final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity) 1350 & Gravity.VERTICAL_GRAVITY_MASK; 1351 final int index = ((gravity >> Gravity.AXIS_Y_SHIFT) 1352 & ~Gravity.AXIS_SPECIFIED) >> 1; 1353 1354 maxAscent[index] = Math.max(maxAscent[index], childBaseline); 1355 maxDescent[index] = Math.max(maxDescent[index], 1356 childHeight - childBaseline); 1357 } 1358 } 1359 } 1360 1361 // Add in our padding 1362 mTotalLength += mPaddingLeft + mPaddingRight; 1363 // TODO: Should we update widthSize with the new total length? 1364 1365 // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP, 1366 // the most common case 1367 if (maxAscent[INDEX_TOP] != -1 || 1368 maxAscent[INDEX_CENTER_VERTICAL] != -1 || 1369 maxAscent[INDEX_BOTTOM] != -1 || 1370 maxAscent[INDEX_FILL] != -1) { 1371 final int ascent = Math.max(maxAscent[INDEX_FILL], 1372 Math.max(maxAscent[INDEX_CENTER_VERTICAL], 1373 Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM]))); 1374 final int descent = Math.max(maxDescent[INDEX_FILL], 1375 Math.max(maxDescent[INDEX_CENTER_VERTICAL], 1376 Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM]))); 1377 maxHeight = Math.max(maxHeight, ascent + descent); 1378 } 1379 } else { 1380 alternativeMaxHeight = Math.max(alternativeMaxHeight, weightedMaxHeight); 1381 1382 // We have no limit, so make all weighted views as wide as the largest child. 1383 // Children will have already been measured once. 1384 if (useLargestChild && widthMode != MeasureSpec.EXACTLY) { 1385 for (int i = 0; i < count; i++) { 1386 final View child = getVirtualChildAt(i); 1387 if (child == null || child.getVisibility() == View.GONE) { 1388 continue; 1389 } 1390 1391 final LinearLayout.LayoutParams lp = 1392 (LinearLayout.LayoutParams) child.getLayoutParams(); 1393 1394 float childExtra = lp.weight; 1395 if (childExtra > 0) { 1396 child.measure( 1397 MeasureSpec.makeMeasureSpec(largestChildWidth, MeasureSpec.EXACTLY), 1398 MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(), 1399 MeasureSpec.EXACTLY)); 1400 } 1401 } 1402 } 1403 } 1404 1405 if (!allFillParent && heightMode != MeasureSpec.EXACTLY) { 1406 maxHeight = alternativeMaxHeight; 1407 } 1408 1409 maxHeight += mPaddingTop + mPaddingBottom; 1410 1411 // Check against our minimum height 1412 maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight()); 1413 1414 setMeasuredDimension(widthSizeAndState | (childState&MEASURED_STATE_MASK), 1415 resolveSizeAndState(maxHeight, heightMeasureSpec, 1416 (childState<<MEASURED_HEIGHT_STATE_SHIFT))); 1417 1418 if (matchHeight) { 1419 forceUniformHeight(count, widthMeasureSpec); 1420 } 1421 } 1422 1423 private void forceUniformHeight(int count, int widthMeasureSpec) { 1424 // Pretend that the linear layout has an exact size. This is the measured height of 1425 // ourselves. The measured height should be the max height of the children, changed 1426 // to accommodate the heightMeasureSpec from the parent 1427 int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), 1428 MeasureSpec.EXACTLY); 1429 for (int i = 0; i < count; ++i) { 1430 final View child = getVirtualChildAt(i); 1431 if (child != null && child.getVisibility() != GONE) { 1432 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams(); 1433 1434 if (lp.height == LayoutParams.MATCH_PARENT) { 1435 // Temporarily force children to reuse their old measured width 1436 // FIXME: this may not be right for something like wrapping text? 1437 int oldWidth = lp.width; 1438 lp.width = child.getMeasuredWidth(); 1439 1440 // Remeasure with new dimensions 1441 measureChildWithMargins(child, widthMeasureSpec, 0, uniformMeasureSpec, 0); 1442 lp.width = oldWidth; 1443 } 1444 } 1445 } 1446 } 1447 1448 /** 1449 * <p>Returns the number of children to skip after measuring/laying out 1450 * the specified child.</p> 1451 * 1452 * @param child the child after which we want to skip children 1453 * @param index the index of the child after which we want to skip children 1454 * @return the number of children to skip, 0 by default 1455 */ 1456 int getChildrenSkipCount(View child, int index) { 1457 return 0; 1458 } 1459 1460 /** 1461 * <p>Returns the size (width or height) that should be occupied by a null 1462 * child.</p> 1463 * 1464 * @param childIndex the index of the null child 1465 * @return the width or height of the child depending on the orientation 1466 */ 1467 int measureNullChild(int childIndex) { 1468 return 0; 1469 } 1470 1471 /** 1472 * <p>Measure the child according to the parent's measure specs. This 1473 * method should be overriden by subclasses to force the sizing of 1474 * children. This method is called by {@link #measureVertical(int, int)} and 1475 * {@link #measureHorizontal(int, int)}.</p> 1476 * 1477 * @param child the child to measure 1478 * @param childIndex the index of the child in this view 1479 * @param widthMeasureSpec horizontal space requirements as imposed by the parent 1480 * @param totalWidth extra space that has been used up by the parent horizontally 1481 * @param heightMeasureSpec vertical space requirements as imposed by the parent 1482 * @param totalHeight extra space that has been used up by the parent vertically 1483 */ 1484 void measureChildBeforeLayout(View child, int childIndex, 1485 int widthMeasureSpec, int totalWidth, int heightMeasureSpec, 1486 int totalHeight) { 1487 measureChildWithMargins(child, widthMeasureSpec, totalWidth, 1488 heightMeasureSpec, totalHeight); 1489 } 1490 1491 /** 1492 * <p>Return the location offset of the specified child. This can be used 1493 * by subclasses to change the location of a given widget.</p> 1494 * 1495 * @param child the child for which to obtain the location offset 1496 * @return the location offset in pixels 1497 */ 1498 int getLocationOffset(View child) { 1499 return 0; 1500 } 1501 1502 /** 1503 * <p>Return the size offset of the next sibling of the specified child. 1504 * This can be used by subclasses to change the location of the widget 1505 * following <code>child</code>.</p> 1506 * 1507 * @param child the child whose next sibling will be moved 1508 * @return the location offset of the next child in pixels 1509 */ 1510 int getNextLocationOffset(View child) { 1511 return 0; 1512 } 1513 1514 @Override 1515 protected void onLayout(boolean changed, int l, int t, int r, int b) { 1516 if (mOrientation == VERTICAL) { 1517 layoutVertical(l, t, r, b); 1518 } else { 1519 layoutHorizontal(l, t, r, b); 1520 } 1521 } 1522 1523 /** 1524 * Position the children during a layout pass if the orientation of this 1525 * LinearLayout is set to {@link #VERTICAL}. 1526 * 1527 * @see #getOrientation() 1528 * @see #setOrientation(int) 1529 * @see #onLayout(boolean, int, int, int, int) 1530 * @param left 1531 * @param top 1532 * @param right 1533 * @param bottom 1534 */ 1535 void layoutVertical(int left, int top, int right, int bottom) { 1536 final int paddingLeft = mPaddingLeft; 1537 1538 int childTop; 1539 int childLeft; 1540 1541 // Where right end of child should go 1542 final int width = right - left; 1543 int childRight = width - mPaddingRight; 1544 1545 // Space available for child 1546 int childSpace = width - paddingLeft - mPaddingRight; 1547 1548 final int count = getVirtualChildCount(); 1549 1550 final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK; 1551 final int minorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK; 1552 1553 switch (majorGravity) { 1554 case Gravity.BOTTOM: 1555 // mTotalLength contains the padding already 1556 childTop = mPaddingTop + bottom - top - mTotalLength; 1557 break; 1558 1559 // mTotalLength contains the padding already 1560 case Gravity.CENTER_VERTICAL: 1561 childTop = mPaddingTop + (bottom - top - mTotalLength) / 2; 1562 break; 1563 1564 case Gravity.TOP: 1565 default: 1566 childTop = mPaddingTop; 1567 break; 1568 } 1569 1570 for (int i = 0; i < count; i++) { 1571 final View child = getVirtualChildAt(i); 1572 if (child == null) { 1573 childTop += measureNullChild(i); 1574 } else if (child.getVisibility() != GONE) { 1575 final int childWidth = child.getMeasuredWidth(); 1576 final int childHeight = child.getMeasuredHeight(); 1577 1578 final LinearLayout.LayoutParams lp = 1579 (LinearLayout.LayoutParams) child.getLayoutParams(); 1580 1581 int gravity = lp.gravity; 1582 if (gravity < 0) { 1583 gravity = minorGravity; 1584 } 1585 final int layoutDirection = getLayoutDirection(); 1586 final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection); 1587 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { 1588 case Gravity.CENTER_HORIZONTAL: 1589 childLeft = paddingLeft + ((childSpace - childWidth) / 2) 1590 + lp.leftMargin - lp.rightMargin; 1591 break; 1592 1593 case Gravity.RIGHT: 1594 childLeft = childRight - childWidth - lp.rightMargin; 1595 break; 1596 1597 case Gravity.LEFT: 1598 default: 1599 childLeft = paddingLeft + lp.leftMargin; 1600 break; 1601 } 1602 1603 if (hasDividerBeforeChildAt(i)) { 1604 childTop += mDividerHeight; 1605 } 1606 1607 childTop += lp.topMargin; 1608 setChildFrame(child, childLeft, childTop + getLocationOffset(child), 1609 childWidth, childHeight); 1610 childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child); 1611 1612 i += getChildrenSkipCount(child, i); 1613 } 1614 } 1615 } 1616 1617 @Override 1618 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 1619 super.onRtlPropertiesChanged(layoutDirection); 1620 if (layoutDirection != mLayoutDirection) { 1621 mLayoutDirection = layoutDirection; 1622 if (mOrientation == HORIZONTAL) { 1623 requestLayout(); 1624 } 1625 } 1626 } 1627 1628 /** 1629 * Position the children during a layout pass if the orientation of this 1630 * LinearLayout is set to {@link #HORIZONTAL}. 1631 * 1632 * @see #getOrientation() 1633 * @see #setOrientation(int) 1634 * @see #onLayout(boolean, int, int, int, int) 1635 * @param left 1636 * @param top 1637 * @param right 1638 * @param bottom 1639 */ 1640 void layoutHorizontal(int left, int top, int right, int bottom) { 1641 final boolean isLayoutRtl = isLayoutRtl(); 1642 final int paddingTop = mPaddingTop; 1643 1644 int childTop; 1645 int childLeft; 1646 1647 // Where bottom of child should go 1648 final int height = bottom - top; 1649 int childBottom = height - mPaddingBottom; 1650 1651 // Space available for child 1652 int childSpace = height - paddingTop - mPaddingBottom; 1653 1654 final int count = getVirtualChildCount(); 1655 1656 final int majorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK; 1657 final int minorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK; 1658 1659 final boolean baselineAligned = mBaselineAligned; 1660 1661 final int[] maxAscent = mMaxAscent; 1662 final int[] maxDescent = mMaxDescent; 1663 1664 final int layoutDirection = getLayoutDirection(); 1665 switch (Gravity.getAbsoluteGravity(majorGravity, layoutDirection)) { 1666 case Gravity.RIGHT: 1667 // mTotalLength contains the padding already 1668 childLeft = mPaddingLeft + right - left - mTotalLength; 1669 break; 1670 1671 case Gravity.CENTER_HORIZONTAL: 1672 // mTotalLength contains the padding already 1673 childLeft = mPaddingLeft + (right - left - mTotalLength) / 2; 1674 break; 1675 1676 case Gravity.LEFT: 1677 default: 1678 childLeft = mPaddingLeft; 1679 break; 1680 } 1681 1682 int start = 0; 1683 int dir = 1; 1684 //In case of RTL, start drawing from the last child. 1685 if (isLayoutRtl) { 1686 start = count - 1; 1687 dir = -1; 1688 } 1689 1690 for (int i = 0; i < count; i++) { 1691 final int childIndex = start + dir * i; 1692 final View child = getVirtualChildAt(childIndex); 1693 if (child == null) { 1694 childLeft += measureNullChild(childIndex); 1695 } else if (child.getVisibility() != GONE) { 1696 final int childWidth = child.getMeasuredWidth(); 1697 final int childHeight = child.getMeasuredHeight(); 1698 int childBaseline = -1; 1699 1700 final LinearLayout.LayoutParams lp = 1701 (LinearLayout.LayoutParams) child.getLayoutParams(); 1702 1703 if (baselineAligned && lp.height != LayoutParams.MATCH_PARENT) { 1704 childBaseline = child.getBaseline(); 1705 } 1706 1707 int gravity = lp.gravity; 1708 if (gravity < 0) { 1709 gravity = minorGravity; 1710 } 1711 1712 switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) { 1713 case Gravity.TOP: 1714 childTop = paddingTop + lp.topMargin; 1715 if (childBaseline != -1) { 1716 childTop += maxAscent[INDEX_TOP] - childBaseline; 1717 } 1718 break; 1719 1720 case Gravity.CENTER_VERTICAL: 1721 // Removed support for baseline alignment when layout_gravity or 1722 // gravity == center_vertical. See bug #1038483. 1723 // Keep the code around if we need to re-enable this feature 1724 // if (childBaseline != -1) { 1725 // // Align baselines vertically only if the child is smaller than us 1726 // if (childSpace - childHeight > 0) { 1727 // childTop = paddingTop + (childSpace / 2) - childBaseline; 1728 // } else { 1729 // childTop = paddingTop + (childSpace - childHeight) / 2; 1730 // } 1731 // } else { 1732 childTop = paddingTop + ((childSpace - childHeight) / 2) 1733 + lp.topMargin - lp.bottomMargin; 1734 break; 1735 1736 case Gravity.BOTTOM: 1737 childTop = childBottom - childHeight - lp.bottomMargin; 1738 if (childBaseline != -1) { 1739 int descent = child.getMeasuredHeight() - childBaseline; 1740 childTop -= (maxDescent[INDEX_BOTTOM] - descent); 1741 } 1742 break; 1743 default: 1744 childTop = paddingTop; 1745 break; 1746 } 1747 1748 if (hasDividerBeforeChildAt(childIndex)) { 1749 childLeft += mDividerWidth; 1750 } 1751 1752 childLeft += lp.leftMargin; 1753 setChildFrame(child, childLeft + getLocationOffset(child), childTop, 1754 childWidth, childHeight); 1755 childLeft += childWidth + lp.rightMargin + 1756 getNextLocationOffset(child); 1757 1758 i += getChildrenSkipCount(child, childIndex); 1759 } 1760 } 1761 } 1762 1763 private void setChildFrame(View child, int left, int top, int width, int height) { 1764 child.layout(left, top, left + width, top + height); 1765 } 1766 1767 /** 1768 * Should the layout be a column or a row. 1769 * @param orientation Pass {@link #HORIZONTAL} or {@link #VERTICAL}. Default 1770 * value is {@link #HORIZONTAL}. 1771 * 1772 * @attr ref android.R.styleable#LinearLayout_orientation 1773 */ 1774 public void setOrientation(@OrientationMode int orientation) { 1775 if (mOrientation != orientation) { 1776 mOrientation = orientation; 1777 requestLayout(); 1778 } 1779 } 1780 1781 /** 1782 * Returns the current orientation. 1783 * 1784 * @return either {@link #HORIZONTAL} or {@link #VERTICAL} 1785 */ 1786 @OrientationMode 1787 public int getOrientation() { 1788 return mOrientation; 1789 } 1790 1791 /** 1792 * Describes how the child views are positioned. Defaults to GRAVITY_TOP. If 1793 * this layout has a VERTICAL orientation, this controls where all the child 1794 * views are placed if there is extra vertical space. If this layout has a 1795 * HORIZONTAL orientation, this controls the alignment of the children. 1796 * 1797 * @param gravity See {@link android.view.Gravity} 1798 * 1799 * @attr ref android.R.styleable#LinearLayout_gravity 1800 */ 1801 @android.view.RemotableViewMethod 1802 public void setGravity(int gravity) { 1803 if (mGravity != gravity) { 1804 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 1805 gravity |= Gravity.START; 1806 } 1807 1808 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 1809 gravity |= Gravity.TOP; 1810 } 1811 1812 mGravity = gravity; 1813 requestLayout(); 1814 } 1815 } 1816 1817 /** 1818 * Returns the current gravity. See {@link android.view.Gravity} 1819 * 1820 * @return the current gravity. 1821 * @see #setGravity 1822 */ 1823 public int getGravity() { 1824 return mGravity; 1825 } 1826 1827 @android.view.RemotableViewMethod 1828 public void setHorizontalGravity(int horizontalGravity) { 1829 final int gravity = horizontalGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK; 1830 if ((mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) != gravity) { 1831 mGravity = (mGravity & ~Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) | gravity; 1832 requestLayout(); 1833 } 1834 } 1835 1836 @android.view.RemotableViewMethod 1837 public void setVerticalGravity(int verticalGravity) { 1838 final int gravity = verticalGravity & Gravity.VERTICAL_GRAVITY_MASK; 1839 if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != gravity) { 1840 mGravity = (mGravity & ~Gravity.VERTICAL_GRAVITY_MASK) | gravity; 1841 requestLayout(); 1842 } 1843 } 1844 1845 @Override 1846 public LayoutParams generateLayoutParams(AttributeSet attrs) { 1847 return new LinearLayout.LayoutParams(getContext(), attrs); 1848 } 1849 1850 /** 1851 * Returns a set of layout parameters with a width of 1852 * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT} 1853 * and a height of {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} 1854 * when the layout's orientation is {@link #VERTICAL}. When the orientation is 1855 * {@link #HORIZONTAL}, the width is set to {@link LayoutParams#WRAP_CONTENT} 1856 * and the height to {@link LayoutParams#WRAP_CONTENT}. 1857 */ 1858 @Override 1859 protected LayoutParams generateDefaultLayoutParams() { 1860 if (mOrientation == HORIZONTAL) { 1861 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 1862 } else if (mOrientation == VERTICAL) { 1863 return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 1864 } 1865 return null; 1866 } 1867 1868 @Override 1869 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) { 1870 if (lp instanceof LayoutParams) { 1871 return new LayoutParams((LayoutParams) lp); 1872 } else if (lp instanceof MarginLayoutParams) { 1873 return new LayoutParams((MarginLayoutParams) lp); 1874 } else { 1875 return new LayoutParams(lp); 1876 } 1877 } 1878 1879 1880 // Override to allow type-checking of LayoutParams. 1881 @Override 1882 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 1883 return p instanceof LinearLayout.LayoutParams; 1884 } 1885 1886 @Override 1887 public CharSequence getAccessibilityClassName() { 1888 return LinearLayout.class.getName(); 1889 } 1890 1891 /** @hide */ 1892 @Override 1893 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) { 1894 super.encodeProperties(encoder); 1895 encoder.addProperty("layout:baselineAligned", mBaselineAligned); 1896 encoder.addProperty("layout:baselineAlignedChildIndex", mBaselineAlignedChildIndex); 1897 encoder.addProperty("measurement:baselineChildTop", mBaselineChildTop); 1898 encoder.addProperty("measurement:orientation", mOrientation); 1899 encoder.addProperty("measurement:gravity", mGravity); 1900 encoder.addProperty("measurement:totalLength", mTotalLength); 1901 encoder.addProperty("layout:totalLength", mTotalLength); 1902 encoder.addProperty("layout:useLargestChild", mUseLargestChild); 1903 } 1904 1905 /** 1906 * Per-child layout information associated with ViewLinearLayout. 1907 * 1908 * @attr ref android.R.styleable#LinearLayout_Layout_layout_weight 1909 * @attr ref android.R.styleable#LinearLayout_Layout_layout_gravity 1910 */ 1911 public static class LayoutParams extends ViewGroup.MarginLayoutParams { 1912 /** 1913 * Indicates how much of the extra space in the LinearLayout will be 1914 * allocated to the view associated with these LayoutParams. Specify 1915 * 0 if the view should not be stretched. Otherwise the extra pixels 1916 * will be pro-rated among all views whose weight is greater than 0. 1917 */ 1918 @ViewDebug.ExportedProperty(category = "layout") 1919 public float weight; 1920 1921 /** 1922 * Gravity for the view associated with these LayoutParams. 1923 * 1924 * @see android.view.Gravity 1925 */ 1926 @ViewDebug.ExportedProperty(category = "layout", mapping = { 1927 @ViewDebug.IntToString(from = -1, to = "NONE"), 1928 @ViewDebug.IntToString(from = Gravity.NO_GRAVITY, to = "NONE"), 1929 @ViewDebug.IntToString(from = Gravity.TOP, to = "TOP"), 1930 @ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"), 1931 @ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"), 1932 @ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"), 1933 @ViewDebug.IntToString(from = Gravity.START, to = "START"), 1934 @ViewDebug.IntToString(from = Gravity.END, to = "END"), 1935 @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"), 1936 @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"), 1937 @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"), 1938 @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL, to = "FILL_HORIZONTAL"), 1939 @ViewDebug.IntToString(from = Gravity.CENTER, to = "CENTER"), 1940 @ViewDebug.IntToString(from = Gravity.FILL, to = "FILL") 1941 }) 1942 public int gravity = -1; 1943 1944 /** 1945 * {@inheritDoc} 1946 */ 1947 public LayoutParams(Context c, AttributeSet attrs) { 1948 super(c, attrs); 1949 TypedArray a = 1950 c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout_Layout); 1951 1952 weight = a.getFloat(com.android.internal.R.styleable.LinearLayout_Layout_layout_weight, 0); 1953 gravity = a.getInt(com.android.internal.R.styleable.LinearLayout_Layout_layout_gravity, -1); 1954 1955 a.recycle(); 1956 } 1957 1958 /** 1959 * {@inheritDoc} 1960 */ 1961 public LayoutParams(int width, int height) { 1962 super(width, height); 1963 weight = 0; 1964 } 1965 1966 /** 1967 * Creates a new set of layout parameters with the specified width, height 1968 * and weight. 1969 * 1970 * @param width the width, either {@link #MATCH_PARENT}, 1971 * {@link #WRAP_CONTENT} or a fixed size in pixels 1972 * @param height the height, either {@link #MATCH_PARENT}, 1973 * {@link #WRAP_CONTENT} or a fixed size in pixels 1974 * @param weight the weight 1975 */ 1976 public LayoutParams(int width, int height, float weight) { 1977 super(width, height); 1978 this.weight = weight; 1979 } 1980 1981 /** 1982 * {@inheritDoc} 1983 */ 1984 public LayoutParams(ViewGroup.LayoutParams p) { 1985 super(p); 1986 } 1987 1988 /** 1989 * {@inheritDoc} 1990 */ 1991 public LayoutParams(ViewGroup.MarginLayoutParams source) { 1992 super(source); 1993 } 1994 1995 /** 1996 * Copy constructor. Clones the width, height, margin values, weight, 1997 * and gravity of the source. 1998 * 1999 * @param source The layout params to copy from. 2000 */ 2001 public LayoutParams(LayoutParams source) { 2002 super(source); 2003 2004 this.weight = source.weight; 2005 this.gravity = source.gravity; 2006 } 2007 2008 @Override 2009 public String debug(String output) { 2010 return output + "LinearLayout.LayoutParams={width=" + sizeToString(width) + 2011 ", height=" + sizeToString(height) + " weight=" + weight + "}"; 2012 } 2013 2014 /** @hide */ 2015 @Override 2016 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) { 2017 super.encodeProperties(encoder); 2018 2019 encoder.addProperty("layout:weight", weight); 2020 encoder.addProperty("layout:gravity", gravity); 2021 } 2022 } 2023} 2024