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