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