LinearLayout.java revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
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 android.content.Context; 20import android.content.res.TypedArray; 21import android.util.AttributeSet; 22import android.view.Gravity; 23import android.view.View; 24import android.view.ViewDebug; 25import android.view.ViewGroup; 26import android.widget.RemoteViews.RemoteView; 27 28import com.android.internal.R; 29 30 31/** 32 * A Layout that arranges its children in a single column or a single row. The direction of 33 * the row can be set by calling {@link #setOrientation(int) setOrientation()}. 34 * You can also specify gravity, which specifies the alignment of all the child elements by 35 * calling {@link #setGravity(int) setGravity()} or specify that specific children 36 * grow to fill up any remaining space in the layout by setting the <em>weight</em> member of 37 * {@link android.widget.LinearLayout.LayoutParams LinearLayout.LayoutParams}. 38 * The default orientation is horizontal. 39 * 40 * <p> 41 * Also see {@link LinearLayout.LayoutParams android.widget.LinearLayout.LayoutParams} 42 * for layout attributes </p> 43 */ 44@RemoteView 45public class LinearLayout extends ViewGroup { 46 public static final int HORIZONTAL = 0; 47 public static final int VERTICAL = 1; 48 49 /** 50 * Whether the children of this layout are baseline aligned. Only applicable 51 * if {@link #mOrientation} is horizontal. 52 */ 53 private boolean mBaselineAligned = true; 54 55 /** 56 * If this layout is part of another layout that is baseline aligned, 57 * use the child at this index as the baseline. 58 * 59 * Note: this is orthogonal to {@link #mBaselineAligned}, which is concerned 60 * with whether the children of this layout are baseline aligned. 61 */ 62 private int mBaselineAlignedChildIndex = 0; 63 64 /** 65 * The additional offset to the child's baseline. 66 * We'll calculate the baseline of this layout as we measure vertically; for 67 * horizontal linear layouts, the offset of 0 is appropriate. 68 */ 69 private int mBaselineChildTop = 0; 70 71 private int mOrientation; 72 private int mGravity = Gravity.LEFT | Gravity.TOP; 73 private int mTotalLength; 74 75 private float mWeightSum; 76 77 private int[] mMaxAscent; 78 private int[] mMaxDescent; 79 80 private static final int VERTICAL_GRAVITY_COUNT = 4; 81 82 private static final int INDEX_CENTER_VERTICAL = 0; 83 private static final int INDEX_TOP = 1; 84 private static final int INDEX_BOTTOM = 2; 85 private static final int INDEX_FILL = 3; 86 87 public LinearLayout(Context context) { 88 super(context); 89 } 90 91 public LinearLayout(Context context, AttributeSet attrs) { 92 super(context, attrs); 93 94 TypedArray a = 95 context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout); 96 97 int index = a.getInt(com.android.internal.R.styleable.LinearLayout_orientation, -1); 98 if (index >= 0) { 99 setOrientation(index); 100 } 101 102 index = a.getInt(com.android.internal.R.styleable.LinearLayout_gravity, -1); 103 if (index >= 0) { 104 setGravity(index); 105 } 106 107 boolean baselineAligned = a.getBoolean(R.styleable.LinearLayout_baselineAligned, true); 108 if (!baselineAligned) { 109 setBaselineAligned(baselineAligned); 110 } 111 112 mWeightSum = a.getFloat(R.styleable.LinearLayout_weightSum, -1.0f); 113 114 mBaselineAlignedChildIndex = 115 a.getInt(com.android.internal.R.styleable.LinearLayout_baselineAlignedChildIndex, -1); 116 117 a.recycle(); 118 } 119 120 /** 121 * <p>Indicates whether widgets contained within this layout are aligned 122 * on their baseline or not.</p> 123 * 124 * @return true when widgets are baseline-aligned, false otherwise 125 */ 126 public boolean isBaselineAligned() { 127 return mBaselineAligned; 128 } 129 130 /** 131 * <p>Defines whether widgets contained in this layout are 132 * baseline-aligned or not.</p> 133 * 134 * @param baselineAligned true to align widgets on their baseline, 135 * false otherwise 136 * 137 * @attr ref android.R.styleable#LinearLayout_baselineAligned 138 */ 139 public void setBaselineAligned(boolean baselineAligned) { 140 mBaselineAligned = baselineAligned; 141 } 142 143 @Override 144 public int getBaseline() { 145 if (mBaselineAlignedChildIndex < 0) { 146 return super.getBaseline(); 147 } 148 149 if (getChildCount() <= mBaselineAlignedChildIndex) { 150 throw new RuntimeException("mBaselineAlignedChildIndex of LinearLayout " 151 + "set to an index that is out of bounds."); 152 } 153 154 final View child = getChildAt(mBaselineAlignedChildIndex); 155 final int childBaseline = child.getBaseline(); 156 157 if (childBaseline == -1) { 158 if (mBaselineAlignedChildIndex == 0) { 159 // this is just the default case, safe to return -1 160 return -1; 161 } 162 // the user picked an index that points to something that doesn't 163 // know how to calculate its baseline. 164 throw new RuntimeException("mBaselineAlignedChildIndex of LinearLayout " 165 + "points to a View that doesn't know how to get its baseline."); 166 } 167 168 // TODO: This should try to take into account the virtual offsets 169 // (See getNextLocationOffset and getLocationOffset) 170 // We should add to childTop: 171 // sum([getNextLocationOffset(getChildAt(i)) / i < mBaselineAlignedChildIndex]) 172 // and also add: 173 // getLocationOffset(child) 174 int childTop = mBaselineChildTop; 175 176 if (mOrientation == VERTICAL) { 177 final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK; 178 if (majorGravity != Gravity.TOP) { 179 switch (majorGravity) { 180 case Gravity.BOTTOM: 181 childTop = mBottom - mTop - mPaddingBottom - mTotalLength; 182 break; 183 184 case Gravity.CENTER_VERTICAL: 185 childTop += ((mBottom - mTop - mPaddingTop - mPaddingBottom) - 186 mTotalLength) / 2; 187 break; 188 } 189 } 190 } 191 192 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams(); 193 return childTop + lp.topMargin + childBaseline; 194 } 195 196 /** 197 * @return The index of the child that will be used if this layout is 198 * part of a larger layout that is baseline aligned, or -1 if none has 199 * been set. 200 */ 201 public int getBaselineAlignedChildIndex() { 202 return mBaselineAlignedChildIndex; 203 } 204 205 /** 206 * @param i The index of the child that will be used if this layout is 207 * part of a larger layout that is baseline aligned. 208 * 209 * @attr ref android.R.styleable#LinearLayout_baselineAlignedChildIndex 210 */ 211 public void setBaselineAlignedChildIndex(int i) { 212 if ((i < 0) || (i >= getChildCount())) { 213 throw new IllegalArgumentException("base aligned child index out " 214 + "of range (0, " + getChildCount() + ")"); 215 } 216 mBaselineAlignedChildIndex = i; 217 } 218 219 /** 220 * <p>Returns the view at the specified index. This method can be overriden 221 * to take into account virtual children. Refer to 222 * {@link android.widget.TableLayout} and {@link android.widget.TableRow} 223 * for an example.</p> 224 * 225 * @param index the child's index 226 * @return the child at the specified index 227 */ 228 View getVirtualChildAt(int index) { 229 return getChildAt(index); 230 } 231 232 /** 233 * <p>Returns the virtual number of children. This number might be different 234 * than the actual number of children if the layout can hold virtual 235 * children. Refer to 236 * {@link android.widget.TableLayout} and {@link android.widget.TableRow} 237 * for an example.</p> 238 * 239 * @return the virtual number of children 240 */ 241 int getVirtualChildCount() { 242 return getChildCount(); 243 } 244 245 /** 246 * Returns the desired weights sum. 247 * 248 * @return A number greater than 0.0f if the weight sum is defined, or 249 * a number lower than or equals to 0.0f if not weight sum is 250 * to be used. 251 */ 252 public float getWeightSum() { 253 return mWeightSum; 254 } 255 256 /** 257 * Defines the desired weights sum. If unspecified the weights sum is computed 258 * at layout time by adding the layout_weight of each child. 259 * 260 * This can be used for instance to give a single child 50% of the total 261 * available space by giving it a layout_weight of 0.5 and setting the 262 * weightSum to 1.0. 263 * 264 * @param weightSum a number greater than 0.0f, or a number lower than or equals 265 * to 0.0f if the weight sum should be computed from the children's 266 * layout_weight 267 */ 268 public void setWeightSum(float weightSum) { 269 mWeightSum = Math.max(0.0f, weightSum); 270 } 271 272 @Override 273 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 274 if (mOrientation == VERTICAL) { 275 measureVertical(widthMeasureSpec, heightMeasureSpec); 276 } else { 277 measureHorizontal(widthMeasureSpec, heightMeasureSpec); 278 } 279 } 280 281 /** 282 * Measures the children when the orientation of this LinearLayout is set 283 * to {@link #VERTICAL}. 284 * 285 * @param widthMeasureSpec Horizontal space requirements as imposed by the parent. 286 * @param heightMeasureSpec Vertical space requirements as imposed by the parent. 287 * 288 * @see #getOrientation() 289 * @see #setOrientation(int) 290 * @see #onMeasure(int, int) 291 */ 292 void measureVertical(int widthMeasureSpec, int heightMeasureSpec) { 293 mTotalLength = 0; 294 int maxWidth = 0; 295 int alternativeMaxWidth = 0; 296 int weightedMaxWidth = 0; 297 boolean allFillParent = true; 298 float totalWeight = 0; 299 300 final int count = getVirtualChildCount(); 301 302 final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 303 final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 304 305 boolean matchWidth = false; 306 307 final int baselineChildIndex = mBaselineAlignedChildIndex; 308 309 // See how tall everyone is. Also remember max width. 310 for (int i = 0; i < count; ++i) { 311 final View child = getVirtualChildAt(i); 312 313 if (child == null) { 314 mTotalLength += measureNullChild(i); 315 continue; 316 } 317 318 if (child.getVisibility() == View.GONE) { 319 i += getChildrenSkipCount(child, i); 320 continue; 321 } 322 323 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams(); 324 325 totalWeight += lp.weight; 326 327 if (heightMode == MeasureSpec.EXACTLY && lp.height == 0 && lp.weight > 0) { 328 // Optimization: don't bother measuring children who are going to use 329 // leftover space. These views will get measured again down below if 330 // there is any leftover space. 331 mTotalLength += lp.topMargin + lp.bottomMargin; 332 } else { 333 int oldHeight = Integer.MIN_VALUE; 334 335 if (lp.height == 0 && lp.weight > 0) { 336 // heightMode is either UNSPECIFIED OR AT_MOST, and this child 337 // wanted to stretch to fill available space. Translate that to 338 // WRAP_CONTENT so that it does not end up with a height of 0 339 oldHeight = lp.height; 340 lp.height = LayoutParams.WRAP_CONTENT; 341 } 342 343 // Determine how big this child would like to. If this or 344 // previous children have given a weight, then we allow it to 345 // use all available space (and we will shrink things later 346 // if needed). 347 measureChildBeforeLayout( 348 child, i, widthMeasureSpec, 0, heightMeasureSpec, 349 totalWeight == 0 ? mTotalLength : 0); 350 351 if (oldHeight != Integer.MIN_VALUE) { 352 lp.height = oldHeight; 353 } 354 355 mTotalLength += child.getMeasuredHeight() + lp.topMargin + 356 lp.bottomMargin + getNextLocationOffset(child); 357 } 358 359 /** 360 * If applicable, compute the additional offset to the child's baseline 361 * we'll need later when asked {@link #getBaseline}. 362 */ 363 if ((baselineChildIndex >= 0) && (baselineChildIndex == i + 1)) { 364 mBaselineChildTop = mTotalLength; 365 } 366 367 // if we are trying to use a child index for our baseline, the above 368 // book keeping only works if there are no children above it with 369 // weight. fail fast to aid the developer. 370 if (i < baselineChildIndex && lp.weight > 0) { 371 throw new RuntimeException("A child of LinearLayout with index " 372 + "less than mBaselineAlignedChildIndex has weight > 0, which " 373 + "won't work. Either remove the weight, or don't set " 374 + "mBaselineAlignedChildIndex."); 375 } 376 377 boolean matchWidthLocally = false; 378 if (widthMode != MeasureSpec.EXACTLY && lp.width == LayoutParams.FILL_PARENT) { 379 // The width of the linear layout will scale, and at least one 380 // child said it wanted to match our width. Set a flag 381 // indicating that we need to remeasure at least that view when 382 // we know our width. 383 matchWidth = true; 384 matchWidthLocally = true; 385 } 386 387 final int margin = lp.leftMargin + lp.rightMargin; 388 final int measuredWidth = child.getMeasuredWidth() + margin; 389 maxWidth = Math.max(maxWidth, measuredWidth); 390 391 allFillParent = allFillParent && lp.width == LayoutParams.FILL_PARENT; 392 if (lp.weight > 0) { 393 /* 394 * Widths of weighted Views are bogus if we end up 395 * remeasuring, so keep them separate. 396 */ 397 weightedMaxWidth = Math.max(weightedMaxWidth, 398 matchWidthLocally ? margin : measuredWidth); 399 } else { 400 alternativeMaxWidth = Math.max(alternativeMaxWidth, 401 matchWidthLocally ? margin : measuredWidth); 402 } 403 404 i += getChildrenSkipCount(child, i); 405 } 406 407 // Add in our padding 408 mTotalLength += mPaddingTop + mPaddingBottom; 409 410 int heightSize = mTotalLength; 411 412 // Check against our minimum height 413 heightSize = Math.max(heightSize, getSuggestedMinimumHeight()); 414 415 // Reconcile our calculated size with the heightMeasureSpec 416 heightSize = resolveSize(heightSize, heightMeasureSpec); 417 418 // Either expand children with weight to take up available space or 419 // shrink them if they extend beyond our current bounds 420 int delta = heightSize - mTotalLength; 421 if (delta != 0 && totalWeight > 0.0f) { 422 float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight; 423 424 mTotalLength = 0; 425 426 for (int i = 0; i < count; ++i) { 427 final View child = getVirtualChildAt(i); 428 429 if (child.getVisibility() == View.GONE) { 430 continue; 431 } 432 433 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams(); 434 435 float childExtra = lp.weight; 436 if (childExtra > 0) { 437 // Child said it could absorb extra space -- give him his share 438 int share = (int) (childExtra * delta / weightSum); 439 weightSum -= childExtra; 440 delta -= share; 441 442 final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 443 mPaddingLeft + mPaddingRight + 444 lp.leftMargin + lp.rightMargin, lp.width); 445 446 // TODO: Use a field like lp.isMeasured to figure out if this 447 // child has been previously measured 448 if ((lp.height != 0) || (heightMode != MeasureSpec.EXACTLY)) { 449 // child was measured once already above... 450 // base new measurement on stored values 451 int childHeight = child.getMeasuredHeight() + share; 452 if (childHeight < 0) { 453 childHeight = 0; 454 } 455 456 child.measure(childWidthMeasureSpec, 457 MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY)); 458 } else { 459 // child was skipped in the loop above. 460 // Measure for this first time here 461 child.measure(childWidthMeasureSpec, 462 MeasureSpec.makeMeasureSpec(share > 0 ? share : 0, 463 MeasureSpec.EXACTLY)); 464 } 465 } 466 467 final int margin = lp.leftMargin + lp.rightMargin; 468 final int measuredWidth = child.getMeasuredWidth() + margin; 469 maxWidth = Math.max(maxWidth, measuredWidth); 470 471 boolean matchWidthLocally = widthMode != MeasureSpec.EXACTLY && 472 lp.width == LayoutParams.FILL_PARENT; 473 474 alternativeMaxWidth = Math.max(alternativeMaxWidth, 475 matchWidthLocally ? margin : measuredWidth); 476 477 allFillParent = allFillParent && lp.width == LayoutParams.FILL_PARENT; 478 alternativeMaxWidth = Math.max(alternativeMaxWidth, 479 matchWidthLocally ? margin : measuredWidth); 480 481 mTotalLength += child.getMeasuredHeight() + lp.topMargin + 482 lp.bottomMargin + getNextLocationOffset(child); 483 } 484 485 // Add in our padding 486 mTotalLength += mPaddingTop + mPaddingBottom; 487 } else { 488 alternativeMaxWidth = Math.max(alternativeMaxWidth, 489 weightedMaxWidth); 490 } 491 492 if (!allFillParent && widthMode != MeasureSpec.EXACTLY) { 493 maxWidth = alternativeMaxWidth; 494 } 495 496 maxWidth += mPaddingLeft + mPaddingRight; 497 498 // Check against our minimum width 499 maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth()); 500 501 setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), heightSize); 502 503 if (matchWidth) { 504 forceUniformWidth(count, heightMeasureSpec); 505 } 506 } 507 508 private void forceUniformWidth(int count, int heightMeasureSpec) { 509 // Pretend that the linear layout has an exact size. 510 int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), 511 MeasureSpec.EXACTLY); 512 for (int i = 0; i< count; ++i) { 513 final View child = getVirtualChildAt(i); 514 if (child.getVisibility() != GONE) { 515 LinearLayout.LayoutParams lp = ((LinearLayout.LayoutParams)child.getLayoutParams()); 516 517 if (lp.width == LayoutParams.FILL_PARENT) { 518 // Temporarily force children to reuse their old measured height 519 // FIXME: this may not be right for something like wrapping text? 520 int oldHeight = lp.height; 521 lp.height = child.getMeasuredHeight(); 522 523 // Remeasue with new dimensions 524 measureChildWithMargins(child, uniformMeasureSpec, 0, heightMeasureSpec, 0); 525 lp.height = oldHeight; 526 } 527 } 528 } 529 } 530 531 /** 532 * Measures the children when the orientation of this LinearLayout is set 533 * to {@link #HORIZONTAL}. 534 * 535 * @param widthMeasureSpec Horizontal space requirements as imposed by the parent. 536 * @param heightMeasureSpec Vertical space requirements as imposed by the parent. 537 * 538 * @see #getOrientation() 539 * @see #setOrientation(int) 540 * @see #onMeasure(int, int) 541 */ 542 void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec) { 543 mTotalLength = 0; 544 int maxHeight = 0; 545 int alternativeMaxHeight = 0; 546 int weightedMaxHeight = 0; 547 boolean allFillParent = true; 548 float totalWeight = 0; 549 550 final int count = getVirtualChildCount(); 551 552 final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 553 final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 554 555 boolean matchHeight = false; 556 557 if (mMaxAscent == null || mMaxDescent == null) { 558 mMaxAscent = new int[VERTICAL_GRAVITY_COUNT]; 559 mMaxDescent = new int[VERTICAL_GRAVITY_COUNT]; 560 } 561 562 final int[] maxAscent = mMaxAscent; 563 final int[] maxDescent = mMaxDescent; 564 565 maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1; 566 maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1; 567 568 final boolean baselineAligned = mBaselineAligned; 569 570 // See how wide everyone is. Also remember max height. 571 for (int i = 0; i < count; ++i) { 572 final View child = getVirtualChildAt(i); 573 574 if (child == null) { 575 mTotalLength += measureNullChild(i); 576 continue; 577 } 578 579 if (child.getVisibility() == GONE) { 580 i += getChildrenSkipCount(child, i); 581 continue; 582 } 583 584 final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams(); 585 586 totalWeight += lp.weight; 587 588 if (widthMode == MeasureSpec.EXACTLY && lp.width == 0 && lp.weight > 0) { 589 // Optimization: don't bother measuring children who are going to use 590 // leftover space. These views will get measured again down below if 591 // there is any leftover space. 592 mTotalLength += lp.leftMargin + lp.rightMargin; 593 594 // Baseline alignment requires to measure widgets to obtain the 595 // baseline offset (in particular for TextViews). 596 // The following defeats the optimization mentioned above. 597 // Allow the child to use as much space as it wants because we 598 // can shrink things later (and re-measure). 599 if (baselineAligned) { 600 final int freeSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 601 child.measure(freeSpec, freeSpec); 602 } 603 } else { 604 int oldWidth = Integer.MIN_VALUE; 605 606 if (lp.width == 0 && lp.weight > 0) { 607 // widthMode is either UNSPECIFIED OR AT_MOST, and this child 608 // wanted to stretch to fill available space. Translate that to 609 // WRAP_CONTENT so that it does not end up with a width of 0 610 oldWidth = lp.width; 611 lp.width = LayoutParams.WRAP_CONTENT; 612 } 613 614 // Determine how big this child would like to be. If this or 615 // previous children have given a weight, then we allow it to 616 // use all available space (and we will shrink things later 617 // if needed). 618 measureChildBeforeLayout(child, i, widthMeasureSpec, 619 totalWeight == 0 ? mTotalLength : 0, 620 heightMeasureSpec, 0); 621 622 if (oldWidth != Integer.MIN_VALUE) { 623 lp.width = oldWidth; 624 } 625 626 mTotalLength += child.getMeasuredWidth() + lp.leftMargin + 627 lp.rightMargin + getNextLocationOffset(child); 628 } 629 630 boolean matchHeightLocally = false; 631 if (heightMode != MeasureSpec.EXACTLY && lp.height == LayoutParams.FILL_PARENT) { 632 // The height of the linear layout will scale, and at least one 633 // child said it wanted to match our height. Set a flag indicating that 634 // we need to remeasure at least that view when we know our height. 635 matchHeight = true; 636 matchHeightLocally = true; 637 } 638 639 final int margin = lp.topMargin + lp.bottomMargin; 640 final int childHeight = child.getMeasuredHeight() + margin; 641 642 if (baselineAligned) { 643 final int childBaseline = child.getBaseline(); 644 if (childBaseline != -1) { 645 // Translates the child's vertical gravity into an index 646 // in the range 0..VERTICAL_GRAVITY_COUNT 647 final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity) 648 & Gravity.VERTICAL_GRAVITY_MASK; 649 final int index = ((gravity >> Gravity.AXIS_Y_SHIFT) 650 & ~Gravity.AXIS_SPECIFIED) >> 1; 651 652 maxAscent[index] = Math.max(maxAscent[index], childBaseline); 653 maxDescent[index] = Math.max(maxDescent[index], childHeight - childBaseline); 654 } 655 } 656 657 maxHeight = Math.max(maxHeight, childHeight); 658 659 allFillParent = allFillParent && lp.height == LayoutParams.FILL_PARENT; 660 if (lp.weight > 0) { 661 /* 662 * Heights of weighted Views are bogus if we end up 663 * remeasuring, so keep them separate. 664 */ 665 weightedMaxHeight = Math.max(weightedMaxHeight, 666 matchHeightLocally ? margin : childHeight); 667 } else { 668 alternativeMaxHeight = Math.max(alternativeMaxHeight, 669 matchHeightLocally ? margin : childHeight); 670 } 671 672 i += getChildrenSkipCount(child, i); 673 } 674 675 // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP, 676 // the most common case 677 if (maxAscent[INDEX_TOP] != -1 || 678 maxAscent[INDEX_CENTER_VERTICAL] != -1 || 679 maxAscent[INDEX_BOTTOM] != -1 || 680 maxAscent[INDEX_FILL] != -1) { 681 final int ascent = Math.max(maxAscent[INDEX_FILL], 682 Math.max(maxAscent[INDEX_CENTER_VERTICAL], 683 Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM]))); 684 final int descent = Math.max(maxDescent[INDEX_FILL], 685 Math.max(maxDescent[INDEX_CENTER_VERTICAL], 686 Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM]))); 687 maxHeight = Math.max(maxHeight, ascent + descent); 688 } 689 690 // Add in our padding 691 mTotalLength += mPaddingLeft + mPaddingRight; 692 693 int widthSize = mTotalLength; 694 695 // Check against our minimum width 696 widthSize = Math.max(widthSize, getSuggestedMinimumWidth()); 697 698 // Reconcile our calculated size with the widthMeasureSpec 699 widthSize = resolveSize(widthSize, widthMeasureSpec); 700 701 // Either expand children with weight to take up available space or 702 // shrink them if they extend beyond our current bounds 703 int delta = widthSize - mTotalLength; 704 if (delta != 0 && totalWeight > 0.0f) { 705 float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight; 706 707 maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1; 708 maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1; 709 maxHeight = -1; 710 711 mTotalLength = 0; 712 713 for (int i = 0; i < count; ++i) { 714 final View child = getVirtualChildAt(i); 715 716 if (child == null || child.getVisibility() == View.GONE) { 717 continue; 718 } 719 720 final LinearLayout.LayoutParams lp = 721 (LinearLayout.LayoutParams) child.getLayoutParams(); 722 723 float childExtra = lp.weight; 724 if (childExtra > 0) { 725 // Child said it could absorb extra space -- give him his share 726 int share = (int) (childExtra * delta / weightSum); 727 weightSum -= childExtra; 728 delta -= share; 729 730 final int childHeightMeasureSpec = getChildMeasureSpec( 731 heightMeasureSpec, 732 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin, 733 lp.height); 734 735 // TODO: Use a field like lp.isMeasured to figure out if this 736 // child has been previously measured 737 if ((lp.width != 0) || (widthMode != MeasureSpec.EXACTLY)) { 738 // child was measured once already above ... base new measurement 739 // on stored values 740 int childWidth = child.getMeasuredWidth() + share; 741 if (childWidth < 0) { 742 childWidth = 0; 743 } 744 745 child.measure( 746 MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY), 747 childHeightMeasureSpec); 748 } else { 749 // child was skipped in the loop above. Measure for this first time here 750 child.measure(MeasureSpec.makeMeasureSpec( 751 share > 0 ? share : 0, MeasureSpec.EXACTLY), 752 childHeightMeasureSpec); 753 } 754 } 755 756 mTotalLength += child.getMeasuredWidth() + lp.leftMargin + 757 lp.rightMargin + getNextLocationOffset(child); 758 759 boolean matchHeightLocally = heightMode != MeasureSpec.EXACTLY && 760 lp.height == LayoutParams.FILL_PARENT; 761 762 final int margin = lp.topMargin + lp .bottomMargin; 763 int childHeight = child.getMeasuredHeight() + margin; 764 maxHeight = Math.max(maxHeight, childHeight); 765 alternativeMaxHeight = Math.max(alternativeMaxHeight, 766 matchHeightLocally ? margin : childHeight); 767 768 allFillParent = allFillParent && lp.height == LayoutParams.FILL_PARENT; 769 alternativeMaxHeight = Math.max(alternativeMaxHeight, 770 matchHeightLocally ? margin : childHeight); 771 772 if (baselineAligned) { 773 final int childBaseline = child.getBaseline(); 774 if (childBaseline != -1) { 775 // Translates the child's vertical gravity into an index in the range 0..2 776 final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity) 777 & Gravity.VERTICAL_GRAVITY_MASK; 778 final int index = ((gravity >> Gravity.AXIS_Y_SHIFT) 779 & ~Gravity.AXIS_SPECIFIED) >> 1; 780 781 maxAscent[index] = Math.max(maxAscent[index], childBaseline); 782 maxDescent[index] = Math.max(maxDescent[index], 783 childHeight - childBaseline); 784 } 785 } 786 } 787 788 // Add in our padding 789 mTotalLength += mPaddingLeft + mPaddingRight; 790 791 // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP, 792 // the most common case 793 if (maxAscent[INDEX_TOP] != -1 || 794 maxAscent[INDEX_CENTER_VERTICAL] != -1 || 795 maxAscent[INDEX_BOTTOM] != -1 || 796 maxAscent[INDEX_FILL] != -1) { 797 final int ascent = Math.max(maxAscent[INDEX_FILL], 798 Math.max(maxAscent[INDEX_CENTER_VERTICAL], 799 Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM]))); 800 final int descent = Math.max(maxDescent[INDEX_FILL], 801 Math.max(maxDescent[INDEX_CENTER_VERTICAL], 802 Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM]))); 803 maxHeight = Math.max(maxHeight, ascent + descent); 804 } 805 } else { 806 alternativeMaxHeight = Math.max(alternativeMaxHeight, 807 weightedMaxHeight); 808 } 809 810 if (!allFillParent && heightMode != MeasureSpec.EXACTLY) { 811 maxHeight = alternativeMaxHeight; 812 } 813 814 maxHeight += mPaddingTop + mPaddingBottom; 815 816 // Check against our minimum height 817 maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight()); 818 819 setMeasuredDimension(widthSize, resolveSize(maxHeight, heightMeasureSpec)); 820 821 if (matchHeight) { 822 forceUniformHeight(count, widthMeasureSpec); 823 } 824 } 825 826 private void forceUniformHeight(int count, int widthMeasureSpec) { 827 // Pretend that the linear layout has an exact size. This is the measured height of 828 // ourselves. The measured height should be the max height of the children, changed 829 // to accomodate the heightMesureSpec from the parent 830 int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), 831 MeasureSpec.EXACTLY); 832 for (int i = 0; i < count; ++i) { 833 final View child = getVirtualChildAt(i); 834 if (child.getVisibility() != GONE) { 835 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams(); 836 837 if (lp.height == LayoutParams.FILL_PARENT) { 838 // Temporarily force children to reuse their old measured width 839 // FIXME: this may not be right for something like wrapping text? 840 int oldWidth = lp.width; 841 lp.width = child.getMeasuredWidth(); 842 843 // Remeasure with new dimensions 844 measureChildWithMargins(child, widthMeasureSpec, 0, uniformMeasureSpec, 0); 845 lp.width = oldWidth; 846 } 847 } 848 } 849 } 850 851 /** 852 * <p>Returns the number of children to skip after measuring/laying out 853 * the specified child.</p> 854 * 855 * @param child the child after which we want to skip children 856 * @param index the index of the child after which we want to skip children 857 * @return the number of children to skip, 0 by default 858 */ 859 int getChildrenSkipCount(View child, int index) { 860 return 0; 861 } 862 863 /** 864 * <p>Returns the size (width or height) that should be occupied by a null 865 * child.</p> 866 * 867 * @param childIndex the index of the null child 868 * @return the width or height of the child depending on the orientation 869 */ 870 int measureNullChild(int childIndex) { 871 return 0; 872 } 873 874 /** 875 * <p>Measure the child according to the parent's measure specs. This 876 * method should be overriden by subclasses to force the sizing of 877 * children. This method is called by {@link #measureVertical(int, int)} and 878 * {@link #measureHorizontal(int, int)}.</p> 879 * 880 * @param child the child to measure 881 * @param childIndex the index of the child in this view 882 * @param widthMeasureSpec horizontal space requirements as imposed by the parent 883 * @param totalWidth extra space that has been used up by the parent horizontally 884 * @param heightMeasureSpec vertical space requirements as imposed by the parent 885 * @param totalHeight extra space that has been used up by the parent vertically 886 */ 887 void measureChildBeforeLayout(View child, int childIndex, 888 int widthMeasureSpec, int totalWidth, int heightMeasureSpec, 889 int totalHeight) { 890 measureChildWithMargins(child, widthMeasureSpec, totalWidth, 891 heightMeasureSpec, totalHeight); 892 } 893 894 /** 895 * <p>Return the location offset of the specified child. This can be used 896 * by subclasses to change the location of a given widget.</p> 897 * 898 * @param child the child for which to obtain the location offset 899 * @return the location offset in pixels 900 */ 901 int getLocationOffset(View child) { 902 return 0; 903 } 904 905 /** 906 * <p>Return the size offset of the next sibling of the specified child. 907 * This can be used by subclasses to change the location of the widget 908 * following <code>child</code>.</p> 909 * 910 * @param child the child whose next sibling will be moved 911 * @return the location offset of the next child in pixels 912 */ 913 int getNextLocationOffset(View child) { 914 return 0; 915 } 916 917 @Override 918 protected void onLayout(boolean changed, int l, int t, int r, int b) { 919 if (mOrientation == VERTICAL) { 920 layoutVertical(); 921 } else { 922 layoutHorizontal(); 923 } 924 } 925 926 /** 927 * Position the children during a layout pass if the orientation of this 928 * LinearLayout is set to {@link #VERTICAL}. 929 * 930 * @see #getOrientation() 931 * @see #setOrientation(int) 932 * @see #onLayout(boolean, int, int, int, int) 933 */ 934 void layoutVertical() { 935 final int paddingLeft = mPaddingLeft; 936 937 int childTop = mPaddingTop; 938 int childLeft = paddingLeft; 939 940 // Where right end of child should go 941 final int width = mRight - mLeft; 942 int childRight = width - mPaddingRight; 943 944 // Space available for child 945 int childSpace = width - paddingLeft - mPaddingRight; 946 947 final int count = getVirtualChildCount(); 948 949 final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK; 950 final int minorGravity = mGravity & Gravity.HORIZONTAL_GRAVITY_MASK; 951 952 if (majorGravity != Gravity.TOP) { 953 switch (majorGravity) { 954 case Gravity.BOTTOM: 955 childTop = mBottom - mTop - mPaddingBottom - mTotalLength; 956 break; 957 958 case Gravity.CENTER_VERTICAL: 959 childTop += ((mBottom - mTop - mPaddingTop - mPaddingBottom) - 960 mTotalLength) / 2; 961 break; 962 } 963 964 } 965 966 for (int i = 0; i < count; i++) { 967 final View child = getVirtualChildAt(i); 968 if (child == null) { 969 childTop += measureNullChild(i); 970 } else if (child.getVisibility() != GONE) { 971 final int childWidth = child.getMeasuredWidth(); 972 final int childHeight = child.getMeasuredHeight(); 973 974 final LinearLayout.LayoutParams lp = 975 (LinearLayout.LayoutParams) child.getLayoutParams(); 976 977 int gravity = lp.gravity; 978 if (gravity < 0) { 979 gravity = minorGravity; 980 } 981 982 switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) { 983 case Gravity.LEFT: 984 childLeft = paddingLeft + lp.leftMargin; 985 break; 986 987 case Gravity.CENTER_HORIZONTAL: 988 childLeft = paddingLeft + ((childSpace - childWidth) / 2) 989 + lp.leftMargin - lp.rightMargin; 990 break; 991 992 case Gravity.RIGHT: 993 childLeft = childRight - childWidth - lp.rightMargin; 994 break; 995 } 996 997 998 childTop += lp.topMargin; 999 setChildFrame(child, childLeft, childTop + getLocationOffset(child), 1000 childWidth, childHeight); 1001 childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child); 1002 1003 i += getChildrenSkipCount(child, i); 1004 } 1005 } 1006 } 1007 1008 /** 1009 * Position the children during a layout pass if the orientation of this 1010 * LinearLayout is set to {@link #HORIZONTAL}. 1011 * 1012 * @see #getOrientation() 1013 * @see #setOrientation(int) 1014 * @see #onLayout(boolean, int, int, int, int) 1015 */ 1016 void layoutHorizontal() { 1017 final int paddingTop = mPaddingTop; 1018 1019 int childTop = paddingTop; 1020 int childLeft = mPaddingLeft; 1021 1022 // Where bottom of child should go 1023 final int height = mBottom - mTop; 1024 int childBottom = height - mPaddingBottom; 1025 1026 // Space available for child 1027 int childSpace = height - paddingTop - mPaddingBottom; 1028 1029 final int count = getVirtualChildCount(); 1030 1031 final int majorGravity = mGravity & Gravity.HORIZONTAL_GRAVITY_MASK; 1032 final int minorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK; 1033 1034 final boolean baselineAligned = mBaselineAligned; 1035 1036 final int[] maxAscent = mMaxAscent; 1037 final int[] maxDescent = mMaxDescent; 1038 1039 if (majorGravity != Gravity.LEFT) { 1040 switch (majorGravity) { 1041 case Gravity.RIGHT: 1042 childLeft = mRight - mLeft - mPaddingRight - mTotalLength; 1043 break; 1044 1045 case Gravity.CENTER_HORIZONTAL: 1046 childLeft += ((mRight - mLeft - mPaddingLeft - mPaddingRight) - 1047 mTotalLength) / 2; 1048 break; 1049 } 1050 } 1051 1052 for (int i = 0; i < count; i++) { 1053 final View child = getVirtualChildAt(i); 1054 1055 if (child == null) { 1056 childLeft += measureNullChild(i); 1057 } else if (child.getVisibility() != GONE) { 1058 final int childWidth = child.getMeasuredWidth(); 1059 final int childHeight = child.getMeasuredHeight(); 1060 int childBaseline = -1; 1061 1062 final LinearLayout.LayoutParams lp = 1063 (LinearLayout.LayoutParams) child.getLayoutParams(); 1064 1065 if (baselineAligned && lp.height != LayoutParams.FILL_PARENT) { 1066 childBaseline = child.getBaseline(); 1067 } 1068 1069 int gravity = lp.gravity; 1070 if (gravity < 0) { 1071 gravity = minorGravity; 1072 } 1073 1074 switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) { 1075 case Gravity.TOP: 1076 childTop = paddingTop + lp.topMargin; 1077 if (childBaseline != -1) { 1078 childTop += maxAscent[INDEX_TOP] - childBaseline; 1079 } 1080 break; 1081 1082 case Gravity.CENTER_VERTICAL: 1083 // Removed support for baselign alignment when layout_gravity or 1084 // gravity == center_vertical. See bug #1038483. 1085 // Keep the code around if we need to re-enable this feature 1086 // if (childBaseline != -1) { 1087 // // Align baselines vertically only if the child is smaller than us 1088 // if (childSpace - childHeight > 0) { 1089 // childTop = paddingTop + (childSpace / 2) - childBaseline; 1090 // } else { 1091 // childTop = paddingTop + (childSpace - childHeight) / 2; 1092 // } 1093 // } else { 1094 childTop = paddingTop + ((childSpace - childHeight) / 2) 1095 + lp.topMargin - lp.bottomMargin; 1096 break; 1097 1098 case Gravity.BOTTOM: 1099 childTop = childBottom - childHeight - lp.bottomMargin; 1100 if (childBaseline != -1) { 1101 int descent = child.getMeasuredHeight() - childBaseline; 1102 childTop -= (maxDescent[INDEX_BOTTOM] - descent); 1103 } 1104 break; 1105 } 1106 1107 childLeft += lp.leftMargin; 1108 setChildFrame(child, childLeft + getLocationOffset(child), childTop, 1109 childWidth, childHeight); 1110 childLeft += childWidth + lp.rightMargin + 1111 getNextLocationOffset(child); 1112 1113 i += getChildrenSkipCount(child, i); 1114 } 1115 } 1116 } 1117 1118 private void setChildFrame(View child, int left, int top, int width, int height) { 1119 child.layout(left, top, left + width, top + height); 1120 } 1121 1122 /** 1123 * Should the layout be a column or a row. 1124 * @param orientation Pass HORIZONTAL or VERTICAL. Default 1125 * value is HORIZONTAL. 1126 * 1127 * @attr ref android.R.styleable#LinearLayout_orientation 1128 */ 1129 public void setOrientation(int orientation) { 1130 if (mOrientation != orientation) { 1131 mOrientation = orientation; 1132 requestLayout(); 1133 } 1134 } 1135 1136 /** 1137 * Returns the current orientation. 1138 * 1139 * @return either {@link #HORIZONTAL} or {@link #VERTICAL} 1140 */ 1141 public int getOrientation() { 1142 return mOrientation; 1143 } 1144 1145 /** 1146 * Describes how the child views are positioned. Defaults to GRAVITY_TOP. If 1147 * this layout has a VERTICAL orientation, this controls where all the child 1148 * views are placed if there is extra vertical space. If this layout has a 1149 * HORIZONTAL orientation, this controls the alignment of the children. 1150 * 1151 * @param gravity See {@link android.view.Gravity} 1152 * 1153 * @attr ref android.R.styleable#LinearLayout_gravity 1154 */ 1155 public void setGravity(int gravity) { 1156 if (mGravity != gravity) { 1157 if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) { 1158 gravity |= Gravity.LEFT; 1159 } 1160 1161 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 1162 gravity |= Gravity.TOP; 1163 } 1164 1165 mGravity = gravity; 1166 requestLayout(); 1167 } 1168 } 1169 1170 public void setHorizontalGravity(int horizontalGravity) { 1171 final int gravity = horizontalGravity & Gravity.HORIZONTAL_GRAVITY_MASK; 1172 if ((mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != gravity) { 1173 mGravity = (mGravity & ~Gravity.HORIZONTAL_GRAVITY_MASK) | gravity; 1174 requestLayout(); 1175 } 1176 } 1177 1178 public void setVerticalGravity(int verticalGravity) { 1179 final int gravity = verticalGravity & Gravity.VERTICAL_GRAVITY_MASK; 1180 if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != gravity) { 1181 mGravity = (mGravity & ~Gravity.VERTICAL_GRAVITY_MASK) | gravity; 1182 requestLayout(); 1183 } 1184 } 1185 1186 @Override 1187 public LayoutParams generateLayoutParams(AttributeSet attrs) { 1188 return new LinearLayout.LayoutParams(getContext(), attrs); 1189 } 1190 1191 /** 1192 * Returns a set of layout parameters with a width of 1193 * {@link android.view.ViewGroup.LayoutParams#FILL_PARENT} 1194 * and a height of {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} 1195 * when the layout's orientation is {@link #VERTICAL}. When the orientation is 1196 * {@link #HORIZONTAL}, the width is set to {@link LayoutParams#WRAP_CONTENT} 1197 * and the height to {@link LayoutParams#WRAP_CONTENT}. 1198 */ 1199 @Override 1200 protected LayoutParams generateDefaultLayoutParams() { 1201 if (mOrientation == HORIZONTAL) { 1202 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 1203 } else if (mOrientation == VERTICAL) { 1204 return new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); 1205 } 1206 return null; 1207 } 1208 1209 @Override 1210 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 1211 return new LayoutParams(p); 1212 } 1213 1214 1215 // Override to allow type-checking of LayoutParams. 1216 @Override 1217 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 1218 return p instanceof LinearLayout.LayoutParams; 1219 } 1220 1221 /** 1222 * Per-child layout information associated with ViewLinearLayout. 1223 * 1224 * @attr ref android.R.styleable#LinearLayout_Layout_layout_weight 1225 * @attr ref android.R.styleable#LinearLayout_Layout_layout_gravity 1226 */ 1227 public static class LayoutParams extends ViewGroup.MarginLayoutParams { 1228 /** 1229 * Indicates how much of the extra space in the LinearLayout will be 1230 * allocated to the view associated with these LayoutParams. Specify 1231 * 0 if the view should not be stretched. Otherwise the extra pixels 1232 * will be pro-rated among all views whose weight is greater than 0. 1233 */ 1234 @ViewDebug.ExportedProperty 1235 public float weight; 1236 1237 /** 1238 * Gravity for the view associated with these LayoutParams. 1239 * 1240 * @see android.view.Gravity 1241 */ 1242 @ViewDebug.ExportedProperty(mapping = { 1243 @ViewDebug.IntToString(from = -1, to = "NONE"), 1244 @ViewDebug.IntToString(from = Gravity.NO_GRAVITY, to = "NONE"), 1245 @ViewDebug.IntToString(from = Gravity.TOP, to = "TOP"), 1246 @ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"), 1247 @ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"), 1248 @ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"), 1249 @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"), 1250 @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"), 1251 @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"), 1252 @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL, to = "FILL_HORIZONTAL"), 1253 @ViewDebug.IntToString(from = Gravity.CENTER, to = "CENTER"), 1254 @ViewDebug.IntToString(from = Gravity.FILL, to = "FILL") 1255 }) 1256 public int gravity = -1; 1257 1258 /** 1259 * {@inheritDoc} 1260 */ 1261 public LayoutParams(Context c, AttributeSet attrs) { 1262 super(c, attrs); 1263 TypedArray a = 1264 c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout_Layout); 1265 1266 weight = a.getFloat(com.android.internal.R.styleable.LinearLayout_Layout_layout_weight, 0); 1267 gravity = a.getInt(com.android.internal.R.styleable.LinearLayout_Layout_layout_gravity, -1); 1268 1269 a.recycle(); 1270 } 1271 1272 /** 1273 * {@inheritDoc} 1274 */ 1275 public LayoutParams(int width, int height) { 1276 super(width, height); 1277 weight = 0; 1278 } 1279 1280 /** 1281 * Creates a new set of layout parameters with the specified width, height 1282 * and weight. 1283 * 1284 * @param width the width, either {@link #FILL_PARENT}, 1285 * {@link #WRAP_CONTENT} or a fixed size in pixels 1286 * @param height the height, either {@link #FILL_PARENT}, 1287 * {@link #WRAP_CONTENT} or a fixed size in pixels 1288 * @param weight the weight 1289 */ 1290 public LayoutParams(int width, int height, float weight) { 1291 super(width, height); 1292 this.weight = weight; 1293 } 1294 1295 /** 1296 * {@inheritDoc} 1297 */ 1298 public LayoutParams(ViewGroup.LayoutParams p) { 1299 super(p); 1300 } 1301 1302 /** 1303 * {@inheritDoc} 1304 */ 1305 public LayoutParams(MarginLayoutParams source) { 1306 super(source); 1307 } 1308 1309 @Override 1310 public String debug(String output) { 1311 return output + "LinearLayout.LayoutParams={width=" + sizeToString(width) + 1312 ", height=" + sizeToString(height) + " weight=" + weight + "}"; 1313 } 1314 } 1315} 1316