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