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