LinearLayout.java revision 053b48051abab0abd85995a23fcbc172e8c4c57f
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 final int totalLength = mTotalLength; 364 mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin); 365 } else { 366 int oldHeight = Integer.MIN_VALUE; 367 368 if (lp.height == 0 && lp.weight > 0) { 369 // heightMode is either UNSPECIFIED OR AT_MOST, and this child 370 // wanted to stretch to fill available space. Translate that to 371 // WRAP_CONTENT so that it does not end up with a height of 0 372 oldHeight = 0; 373 lp.height = LayoutParams.WRAP_CONTENT; 374 } 375 376 // Determine how big this child would like to. If this or 377 // previous children have given a weight, then we allow it to 378 // use all available space (and we will shrink things later 379 // if needed). 380 measureChildBeforeLayout( 381 child, i, widthMeasureSpec, 0, heightMeasureSpec, 382 totalWeight == 0 ? mTotalLength : 0); 383 384 if (oldHeight != Integer.MIN_VALUE) { 385 lp.height = oldHeight; 386 } 387 388 final int childHeight = child.getMeasuredHeight(); 389 final int totalLength = mTotalLength; 390 mTotalLength = Math.max(totalLength, totalLength + childHeight + lp.topMargin + 391 lp.bottomMargin + getNextLocationOffset(child)); 392 393 if (useLargestChild) { 394 largestChildHeight = Math.max(childHeight, largestChildHeight); 395 } 396 } 397 398 /** 399 * If applicable, compute the additional offset to the child's baseline 400 * we'll need later when asked {@link #getBaseline}. 401 */ 402 if ((baselineChildIndex >= 0) && (baselineChildIndex == i + 1)) { 403 mBaselineChildTop = mTotalLength; 404 } 405 406 // if we are trying to use a child index for our baseline, the above 407 // book keeping only works if there are no children above it with 408 // weight. fail fast to aid the developer. 409 if (i < baselineChildIndex && lp.weight > 0) { 410 throw new RuntimeException("A child of LinearLayout with index " 411 + "less than mBaselineAlignedChildIndex has weight > 0, which " 412 + "won't work. Either remove the weight, or don't set " 413 + "mBaselineAlignedChildIndex."); 414 } 415 416 boolean matchWidthLocally = false; 417 if (widthMode != MeasureSpec.EXACTLY && lp.width == LayoutParams.MATCH_PARENT) { 418 // The width of the linear layout will scale, and at least one 419 // child said it wanted to match our width. Set a flag 420 // indicating that we need to remeasure at least that view when 421 // we know our width. 422 matchWidth = true; 423 matchWidthLocally = true; 424 } 425 426 final int margin = lp.leftMargin + lp.rightMargin; 427 final int measuredWidth = child.getMeasuredWidth() + margin; 428 maxWidth = Math.max(maxWidth, measuredWidth); 429 430 allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT; 431 if (lp.weight > 0) { 432 /* 433 * Widths of weighted Views are bogus if we end up 434 * remeasuring, so keep them separate. 435 */ 436 weightedMaxWidth = Math.max(weightedMaxWidth, 437 matchWidthLocally ? margin : measuredWidth); 438 } else { 439 alternativeMaxWidth = Math.max(alternativeMaxWidth, 440 matchWidthLocally ? margin : measuredWidth); 441 } 442 443 i += getChildrenSkipCount(child, i); 444 } 445 446 if (useLargestChild && heightMode == MeasureSpec.AT_MOST) { 447 mTotalLength = 0; 448 449 for (int i = 0; i < count; ++i) { 450 final View child = getVirtualChildAt(i); 451 452 if (child == null) { 453 mTotalLength += measureNullChild(i); 454 continue; 455 } 456 457 if (child.getVisibility() == GONE) { 458 i += getChildrenSkipCount(child, i); 459 continue; 460 } 461 462 final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) 463 child.getLayoutParams(); 464 // Account for negative margins 465 final int totalLength = mTotalLength; 466 mTotalLength = Math.max(totalLength, totalLength + largestChildHeight + 467 lp.topMargin + lp.bottomMargin + getNextLocationOffset(child)); 468 } 469 } 470 471 // Add in our padding 472 mTotalLength += mPaddingTop + mPaddingBottom; 473 474 int heightSize = mTotalLength; 475 476 // Check against our minimum height 477 heightSize = Math.max(heightSize, getSuggestedMinimumHeight()); 478 479 // Reconcile our calculated size with the heightMeasureSpec 480 heightSize = resolveSize(heightSize, heightMeasureSpec); 481 482 // Either expand children with weight to take up available space or 483 // shrink them if they extend beyond our current bounds 484 int delta = heightSize - mTotalLength; 485 if (delta != 0 && totalWeight > 0.0f) { 486 float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight; 487 488 mTotalLength = 0; 489 490 for (int i = 0; i < count; ++i) { 491 final View child = getVirtualChildAt(i); 492 493 if (child.getVisibility() == View.GONE) { 494 continue; 495 } 496 497 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams(); 498 499 float childExtra = lp.weight; 500 if (childExtra > 0) { 501 // Child said it could absorb extra space -- give him his share 502 int share = (int) (childExtra * delta / weightSum); 503 weightSum -= childExtra; 504 delta -= share; 505 506 final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 507 mPaddingLeft + mPaddingRight + 508 lp.leftMargin + lp.rightMargin, lp.width); 509 510 // TODO: Use a field like lp.isMeasured to figure out if this 511 // child has been previously measured 512 if ((lp.height != 0) || (heightMode != MeasureSpec.EXACTLY)) { 513 // child was measured once already above... 514 // base new measurement on stored values 515 int childHeight = child.getMeasuredHeight() + share; 516 if (childHeight < 0) { 517 childHeight = 0; 518 } 519 520 child.measure(childWidthMeasureSpec, 521 MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY)); 522 } else { 523 // child was skipped in the loop above. 524 // Measure for this first time here 525 child.measure(childWidthMeasureSpec, 526 MeasureSpec.makeMeasureSpec(share > 0 ? share : 0, 527 MeasureSpec.EXACTLY)); 528 } 529 } 530 531 final int margin = lp.leftMargin + lp.rightMargin; 532 final int measuredWidth = child.getMeasuredWidth() + margin; 533 maxWidth = Math.max(maxWidth, measuredWidth); 534 535 boolean matchWidthLocally = widthMode != MeasureSpec.EXACTLY && 536 lp.width == LayoutParams.MATCH_PARENT; 537 538 alternativeMaxWidth = Math.max(alternativeMaxWidth, 539 matchWidthLocally ? margin : measuredWidth); 540 541 allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT; 542 543 final int totalLength = mTotalLength; 544 mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredHeight() + 545 lp.topMargin + lp.bottomMargin + getNextLocationOffset(child)); 546 } 547 548 // Add in our padding 549 mTotalLength += mPaddingTop + mPaddingBottom; 550 // TODO: Should we recompute the heightSpec based on the new total length? 551 } else { 552 alternativeMaxWidth = Math.max(alternativeMaxWidth, 553 weightedMaxWidth); 554 } 555 556 if (!allFillParent && widthMode != MeasureSpec.EXACTLY) { 557 maxWidth = alternativeMaxWidth; 558 } 559 560 maxWidth += mPaddingLeft + mPaddingRight; 561 562 // Check against our minimum width 563 maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth()); 564 565 setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), heightSize); 566 567 if (matchWidth) { 568 forceUniformWidth(count, heightMeasureSpec); 569 } 570 } 571 572 private void forceUniformWidth(int count, int heightMeasureSpec) { 573 // Pretend that the linear layout has an exact size. 574 int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), 575 MeasureSpec.EXACTLY); 576 for (int i = 0; i< count; ++i) { 577 final View child = getVirtualChildAt(i); 578 if (child.getVisibility() != GONE) { 579 LinearLayout.LayoutParams lp = ((LinearLayout.LayoutParams)child.getLayoutParams()); 580 581 if (lp.width == LayoutParams.MATCH_PARENT) { 582 // Temporarily force children to reuse their old measured height 583 // FIXME: this may not be right for something like wrapping text? 584 int oldHeight = lp.height; 585 lp.height = child.getMeasuredHeight(); 586 587 // Remeasue with new dimensions 588 measureChildWithMargins(child, uniformMeasureSpec, 0, heightMeasureSpec, 0); 589 lp.height = oldHeight; 590 } 591 } 592 } 593 } 594 595 /** 596 * Measures the children when the orientation of this LinearLayout is set 597 * to {@link #HORIZONTAL}. 598 * 599 * @param widthMeasureSpec Horizontal space requirements as imposed by the parent. 600 * @param heightMeasureSpec Vertical space requirements as imposed by the parent. 601 * 602 * @see #getOrientation() 603 * @see #setOrientation(int) 604 * @see #onMeasure(int, int) 605 */ 606 void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec) { 607 mTotalLength = 0; 608 int maxHeight = 0; 609 int alternativeMaxHeight = 0; 610 int weightedMaxHeight = 0; 611 boolean allFillParent = true; 612 float totalWeight = 0; 613 614 final int count = getVirtualChildCount(); 615 616 final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 617 final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 618 619 boolean matchHeight = false; 620 621 if (mMaxAscent == null || mMaxDescent == null) { 622 mMaxAscent = new int[VERTICAL_GRAVITY_COUNT]; 623 mMaxDescent = new int[VERTICAL_GRAVITY_COUNT]; 624 } 625 626 final int[] maxAscent = mMaxAscent; 627 final int[] maxDescent = mMaxDescent; 628 629 maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1; 630 maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1; 631 632 final boolean baselineAligned = mBaselineAligned; 633 final boolean useLargestChild = mUseLargestChild; 634 635 int largestChildWidth = Integer.MIN_VALUE; 636 637 // See how wide everyone is. Also remember max height. 638 for (int i = 0; i < count; ++i) { 639 final View child = getVirtualChildAt(i); 640 641 if (child == null) { 642 mTotalLength += measureNullChild(i); 643 continue; 644 } 645 646 if (child.getVisibility() == GONE) { 647 i += getChildrenSkipCount(child, i); 648 continue; 649 } 650 651 final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) 652 child.getLayoutParams(); 653 654 totalWeight += lp.weight; 655 656 if (widthMode == MeasureSpec.EXACTLY && lp.width == 0 && lp.weight > 0) { 657 // Optimization: don't bother measuring children who are going to use 658 // leftover space. These views will get measured again down below if 659 // there is any leftover space. 660 final int totalLength = mTotalLength; 661 mTotalLength = Math.max(totalLength, totalLength + lp.leftMargin + lp.rightMargin); 662 663 // Baseline alignment requires to measure widgets to obtain the 664 // baseline offset (in particular for TextViews). 665 // The following defeats the optimization mentioned above. 666 // Allow the child to use as much space as it wants because we 667 // can shrink things later (and re-measure). 668 if (baselineAligned) { 669 final int freeSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 670 child.measure(freeSpec, freeSpec); 671 } 672 } else { 673 int oldWidth = Integer.MIN_VALUE; 674 675 if (lp.width == 0 && lp.weight > 0) { 676 // widthMode is either UNSPECIFIED OR AT_MOST, and this child 677 // wanted to stretch to fill available space. Translate that to 678 // WRAP_CONTENT so that it does not end up with a width of 0 679 oldWidth = 0; 680 lp.width = LayoutParams.WRAP_CONTENT; 681 } 682 683 // Determine how big this child would like to be. If this or 684 // previous children have given a weight, then we allow it to 685 // use all available space (and we will shrink things later 686 // if needed). 687 measureChildBeforeLayout(child, i, widthMeasureSpec, 688 totalWeight == 0 ? mTotalLength : 0, 689 heightMeasureSpec, 0); 690 691 if (oldWidth != Integer.MIN_VALUE) { 692 lp.width = oldWidth; 693 } 694 695 final int childWidth = child.getMeasuredWidth(); 696 final int totalLength = mTotalLength; 697 mTotalLength = Math.max(totalLength, totalLength + childWidth + lp.leftMargin + 698 lp.rightMargin + getNextLocationOffset(child)); 699 700 if (useLargestChild) { 701 largestChildWidth = Math.max(childWidth, largestChildWidth); 702 } 703 } 704 705 boolean matchHeightLocally = false; 706 if (heightMode != MeasureSpec.EXACTLY && lp.height == LayoutParams.MATCH_PARENT) { 707 // The height of the linear layout will scale, and at least one 708 // child said it wanted to match our height. Set a flag indicating that 709 // we need to remeasure at least that view when we know our height. 710 matchHeight = true; 711 matchHeightLocally = true; 712 } 713 714 final int margin = lp.topMargin + lp.bottomMargin; 715 final int childHeight = child.getMeasuredHeight() + margin; 716 717 if (baselineAligned) { 718 final int childBaseline = child.getBaseline(); 719 if (childBaseline != -1) { 720 // Translates the child's vertical gravity into an index 721 // in the range 0..VERTICAL_GRAVITY_COUNT 722 final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity) 723 & Gravity.VERTICAL_GRAVITY_MASK; 724 final int index = ((gravity >> Gravity.AXIS_Y_SHIFT) 725 & ~Gravity.AXIS_SPECIFIED) >> 1; 726 727 maxAscent[index] = Math.max(maxAscent[index], childBaseline); 728 maxDescent[index] = Math.max(maxDescent[index], childHeight - childBaseline); 729 } 730 } 731 732 maxHeight = Math.max(maxHeight, childHeight); 733 734 allFillParent = allFillParent && lp.height == LayoutParams.MATCH_PARENT; 735 if (lp.weight > 0) { 736 /* 737 * Heights of weighted Views are bogus if we end up 738 * remeasuring, so keep them separate. 739 */ 740 weightedMaxHeight = Math.max(weightedMaxHeight, 741 matchHeightLocally ? margin : childHeight); 742 } else { 743 alternativeMaxHeight = Math.max(alternativeMaxHeight, 744 matchHeightLocally ? margin : childHeight); 745 } 746 747 i += getChildrenSkipCount(child, i); 748 } 749 750 // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP, 751 // the most common case 752 if (maxAscent[INDEX_TOP] != -1 || 753 maxAscent[INDEX_CENTER_VERTICAL] != -1 || 754 maxAscent[INDEX_BOTTOM] != -1 || 755 maxAscent[INDEX_FILL] != -1) { 756 final int ascent = Math.max(maxAscent[INDEX_FILL], 757 Math.max(maxAscent[INDEX_CENTER_VERTICAL], 758 Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM]))); 759 final int descent = Math.max(maxDescent[INDEX_FILL], 760 Math.max(maxDescent[INDEX_CENTER_VERTICAL], 761 Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM]))); 762 maxHeight = Math.max(maxHeight, ascent + descent); 763 } 764 765 if (useLargestChild && widthMode == MeasureSpec.AT_MOST) { 766 mTotalLength = 0; 767 768 for (int i = 0; i < count; ++i) { 769 final View child = getVirtualChildAt(i); 770 771 if (child == null) { 772 mTotalLength += measureNullChild(i); 773 continue; 774 } 775 776 if (child.getVisibility() == GONE) { 777 i += getChildrenSkipCount(child, i); 778 continue; 779 } 780 781 final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) 782 child.getLayoutParams(); 783 final int totalLength = mTotalLength; 784 mTotalLength = Math.max(totalLength, totalLength + largestChildWidth + 785 lp.leftMargin + lp.rightMargin + getNextLocationOffset(child)); 786 } 787 } 788 789 // Add in our padding 790 mTotalLength += mPaddingLeft + mPaddingRight; 791 792 int widthSize = mTotalLength; 793 794 // Check against our minimum width 795 widthSize = Math.max(widthSize, getSuggestedMinimumWidth()); 796 797 // Reconcile our calculated size with the widthMeasureSpec 798 widthSize = resolveSize(widthSize, widthMeasureSpec); 799 800 // Either expand children with weight to take up available space or 801 // shrink them if they extend beyond our current bounds 802 int delta = widthSize - mTotalLength; 803 if (delta != 0 && totalWeight > 0.0f) { 804 float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight; 805 806 maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1; 807 maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1; 808 maxHeight = -1; 809 810 mTotalLength = 0; 811 812 for (int i = 0; i < count; ++i) { 813 final View child = getVirtualChildAt(i); 814 815 if (child == null || child.getVisibility() == View.GONE) { 816 continue; 817 } 818 819 final LinearLayout.LayoutParams lp = 820 (LinearLayout.LayoutParams) child.getLayoutParams(); 821 822 float childExtra = lp.weight; 823 if (childExtra > 0) { 824 // Child said it could absorb extra space -- give him his share 825 int share = (int) (childExtra * delta / weightSum); 826 weightSum -= childExtra; 827 delta -= share; 828 829 final int childHeightMeasureSpec = getChildMeasureSpec( 830 heightMeasureSpec, 831 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin, 832 lp.height); 833 834 // TODO: Use a field like lp.isMeasured to figure out if this 835 // child has been previously measured 836 if ((lp.width != 0) || (widthMode != MeasureSpec.EXACTLY)) { 837 // child was measured once already above ... base new measurement 838 // on stored values 839 int childWidth = child.getMeasuredWidth() + share; 840 if (childWidth < 0) { 841 childWidth = 0; 842 } 843 844 child.measure( 845 MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY), 846 childHeightMeasureSpec); 847 } else { 848 // child was skipped in the loop above. Measure for this first time here 849 child.measure(MeasureSpec.makeMeasureSpec( 850 share > 0 ? share : 0, MeasureSpec.EXACTLY), 851 childHeightMeasureSpec); 852 } 853 } 854 855 final int totalLength = mTotalLength; 856 mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredWidth() + 857 lp.leftMargin + lp.rightMargin + getNextLocationOffset(child)); 858 859 boolean matchHeightLocally = heightMode != MeasureSpec.EXACTLY && 860 lp.height == LayoutParams.MATCH_PARENT; 861 862 final int margin = lp.topMargin + lp .bottomMargin; 863 int childHeight = child.getMeasuredHeight() + margin; 864 maxHeight = Math.max(maxHeight, childHeight); 865 alternativeMaxHeight = Math.max(alternativeMaxHeight, 866 matchHeightLocally ? margin : childHeight); 867 868 allFillParent = allFillParent && lp.height == LayoutParams.MATCH_PARENT; 869 870 if (baselineAligned) { 871 final int childBaseline = child.getBaseline(); 872 if (childBaseline != -1) { 873 // Translates the child's vertical gravity into an index in the range 0..2 874 final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity) 875 & Gravity.VERTICAL_GRAVITY_MASK; 876 final int index = ((gravity >> Gravity.AXIS_Y_SHIFT) 877 & ~Gravity.AXIS_SPECIFIED) >> 1; 878 879 maxAscent[index] = Math.max(maxAscent[index], childBaseline); 880 maxDescent[index] = Math.max(maxDescent[index], 881 childHeight - childBaseline); 882 } 883 } 884 } 885 886 // Add in our padding 887 mTotalLength += mPaddingLeft + mPaddingRight; 888 // TODO: Should we update widthSize with the new total length? 889 890 // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP, 891 // the most common case 892 if (maxAscent[INDEX_TOP] != -1 || 893 maxAscent[INDEX_CENTER_VERTICAL] != -1 || 894 maxAscent[INDEX_BOTTOM] != -1 || 895 maxAscent[INDEX_FILL] != -1) { 896 final int ascent = Math.max(maxAscent[INDEX_FILL], 897 Math.max(maxAscent[INDEX_CENTER_VERTICAL], 898 Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM]))); 899 final int descent = Math.max(maxDescent[INDEX_FILL], 900 Math.max(maxDescent[INDEX_CENTER_VERTICAL], 901 Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM]))); 902 maxHeight = Math.max(maxHeight, ascent + descent); 903 } 904 } else { 905 alternativeMaxHeight = Math.max(alternativeMaxHeight, weightedMaxHeight); 906 } 907 908 if (!allFillParent && heightMode != MeasureSpec.EXACTLY) { 909 maxHeight = alternativeMaxHeight; 910 } 911 912 maxHeight += mPaddingTop + mPaddingBottom; 913 914 // Check against our minimum height 915 maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight()); 916 917 setMeasuredDimension(widthSize, resolveSize(maxHeight, heightMeasureSpec)); 918 919 if (matchHeight) { 920 forceUniformHeight(count, widthMeasureSpec); 921 } 922 } 923 924 private void forceUniformHeight(int count, int widthMeasureSpec) { 925 // Pretend that the linear layout has an exact size. This is the measured height of 926 // ourselves. The measured height should be the max height of the children, changed 927 // to accomodate the heightMesureSpec from the parent 928 int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), 929 MeasureSpec.EXACTLY); 930 for (int i = 0; i < count; ++i) { 931 final View child = getVirtualChildAt(i); 932 if (child.getVisibility() != GONE) { 933 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams(); 934 935 if (lp.height == LayoutParams.MATCH_PARENT) { 936 // Temporarily force children to reuse their old measured width 937 // FIXME: this may not be right for something like wrapping text? 938 int oldWidth = lp.width; 939 lp.width = child.getMeasuredWidth(); 940 941 // Remeasure with new dimensions 942 measureChildWithMargins(child, widthMeasureSpec, 0, uniformMeasureSpec, 0); 943 lp.width = oldWidth; 944 } 945 } 946 } 947 } 948 949 /** 950 * <p>Returns the number of children to skip after measuring/laying out 951 * the specified child.</p> 952 * 953 * @param child the child after which we want to skip children 954 * @param index the index of the child after which we want to skip children 955 * @return the number of children to skip, 0 by default 956 */ 957 int getChildrenSkipCount(View child, int index) { 958 return 0; 959 } 960 961 /** 962 * <p>Returns the size (width or height) that should be occupied by a null 963 * child.</p> 964 * 965 * @param childIndex the index of the null child 966 * @return the width or height of the child depending on the orientation 967 */ 968 int measureNullChild(int childIndex) { 969 return 0; 970 } 971 972 /** 973 * <p>Measure the child according to the parent's measure specs. This 974 * method should be overriden by subclasses to force the sizing of 975 * children. This method is called by {@link #measureVertical(int, int)} and 976 * {@link #measureHorizontal(int, int)}.</p> 977 * 978 * @param child the child to measure 979 * @param childIndex the index of the child in this view 980 * @param widthMeasureSpec horizontal space requirements as imposed by the parent 981 * @param totalWidth extra space that has been used up by the parent horizontally 982 * @param heightMeasureSpec vertical space requirements as imposed by the parent 983 * @param totalHeight extra space that has been used up by the parent vertically 984 */ 985 void measureChildBeforeLayout(View child, int childIndex, 986 int widthMeasureSpec, int totalWidth, int heightMeasureSpec, 987 int totalHeight) { 988 measureChildWithMargins(child, widthMeasureSpec, totalWidth, 989 heightMeasureSpec, totalHeight); 990 } 991 992 /** 993 * <p>Return the location offset of the specified child. This can be used 994 * by subclasses to change the location of a given widget.</p> 995 * 996 * @param child the child for which to obtain the location offset 997 * @return the location offset in pixels 998 */ 999 int getLocationOffset(View child) { 1000 return 0; 1001 } 1002 1003 /** 1004 * <p>Return the size offset of the next sibling of the specified child. 1005 * This can be used by subclasses to change the location of the widget 1006 * following <code>child</code>.</p> 1007 * 1008 * @param child the child whose next sibling will be moved 1009 * @return the location offset of the next child in pixels 1010 */ 1011 int getNextLocationOffset(View child) { 1012 return 0; 1013 } 1014 1015 @Override 1016 protected void onLayout(boolean changed, int l, int t, int r, int b) { 1017 if (mOrientation == VERTICAL) { 1018 layoutVertical(); 1019 } else { 1020 layoutHorizontal(); 1021 } 1022 } 1023 1024 /** 1025 * Position the children during a layout pass if the orientation of this 1026 * LinearLayout is set to {@link #VERTICAL}. 1027 * 1028 * @see #getOrientation() 1029 * @see #setOrientation(int) 1030 * @see #onLayout(boolean, int, int, int, int) 1031 */ 1032 void layoutVertical() { 1033 final int paddingLeft = mPaddingLeft; 1034 1035 int childTop = mPaddingTop; 1036 int childLeft; 1037 1038 // Where right end of child should go 1039 final int width = mRight - mLeft; 1040 int childRight = width - mPaddingRight; 1041 1042 // Space available for child 1043 int childSpace = width - paddingLeft - mPaddingRight; 1044 1045 final int count = getVirtualChildCount(); 1046 1047 final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK; 1048 final int minorGravity = mGravity & Gravity.HORIZONTAL_GRAVITY_MASK; 1049 1050 if (majorGravity != Gravity.TOP) { 1051 switch (majorGravity) { 1052 case Gravity.BOTTOM: 1053 // mTotalLength contains the padding already, we add the top 1054 // padding to compensate 1055 childTop = mBottom - mTop + mPaddingTop - mTotalLength; 1056 break; 1057 1058 case Gravity.CENTER_VERTICAL: 1059 childTop += ((mBottom - mTop) - mTotalLength) / 2; 1060 break; 1061 } 1062 1063 } 1064 1065 for (int i = 0; i < count; i++) { 1066 final View child = getVirtualChildAt(i); 1067 if (child == null) { 1068 childTop += measureNullChild(i); 1069 } else if (child.getVisibility() != GONE) { 1070 final int childWidth = child.getMeasuredWidth(); 1071 final int childHeight = child.getMeasuredHeight(); 1072 1073 final LinearLayout.LayoutParams lp = 1074 (LinearLayout.LayoutParams) child.getLayoutParams(); 1075 1076 int gravity = lp.gravity; 1077 if (gravity < 0) { 1078 gravity = minorGravity; 1079 } 1080 1081 switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) { 1082 case Gravity.LEFT: 1083 childLeft = paddingLeft + lp.leftMargin; 1084 break; 1085 1086 case Gravity.CENTER_HORIZONTAL: 1087 childLeft = paddingLeft + ((childSpace - childWidth) / 2) 1088 + lp.leftMargin - lp.rightMargin; 1089 break; 1090 1091 case Gravity.RIGHT: 1092 childLeft = childRight - childWidth - lp.rightMargin; 1093 break; 1094 default: 1095 childLeft = paddingLeft; 1096 break; 1097 } 1098 1099 1100 childTop += lp.topMargin; 1101 setChildFrame(child, childLeft, childTop + getLocationOffset(child), 1102 childWidth, childHeight); 1103 childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child); 1104 1105 i += getChildrenSkipCount(child, i); 1106 } 1107 } 1108 } 1109 1110 /** 1111 * Position the children during a layout pass if the orientation of this 1112 * LinearLayout is set to {@link #HORIZONTAL}. 1113 * 1114 * @see #getOrientation() 1115 * @see #setOrientation(int) 1116 * @see #onLayout(boolean, int, int, int, int) 1117 */ 1118 void layoutHorizontal() { 1119 final int paddingTop = mPaddingTop; 1120 1121 int childTop; 1122 int childLeft = mPaddingLeft; 1123 1124 // Where bottom of child should go 1125 final int height = mBottom - mTop; 1126 int childBottom = height - mPaddingBottom; 1127 1128 // Space available for child 1129 int childSpace = height - paddingTop - mPaddingBottom; 1130 1131 final int count = getVirtualChildCount(); 1132 1133 final int majorGravity = mGravity & Gravity.HORIZONTAL_GRAVITY_MASK; 1134 final int minorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK; 1135 1136 final boolean baselineAligned = mBaselineAligned; 1137 1138 final int[] maxAscent = mMaxAscent; 1139 final int[] maxDescent = mMaxDescent; 1140 1141 if (majorGravity != Gravity.LEFT) { 1142 switch (majorGravity) { 1143 case Gravity.RIGHT: 1144 // mTotalLength contains the padding already, we add the left 1145 // padding to compensate 1146 childLeft = mRight - mLeft + mPaddingLeft - mTotalLength; 1147 break; 1148 1149 case Gravity.CENTER_HORIZONTAL: 1150 childLeft += ((mRight - mLeft) - mTotalLength) / 2; 1151 break; 1152 } 1153 } 1154 1155 for (int i = 0; i < count; i++) { 1156 final View child = getVirtualChildAt(i); 1157 1158 if (child == null) { 1159 childLeft += measureNullChild(i); 1160 } else if (child.getVisibility() != GONE) { 1161 final int childWidth = child.getMeasuredWidth(); 1162 final int childHeight = child.getMeasuredHeight(); 1163 int childBaseline = -1; 1164 1165 final LinearLayout.LayoutParams lp = 1166 (LinearLayout.LayoutParams) child.getLayoutParams(); 1167 1168 if (baselineAligned && lp.height != LayoutParams.MATCH_PARENT) { 1169 childBaseline = child.getBaseline(); 1170 } 1171 1172 int gravity = lp.gravity; 1173 if (gravity < 0) { 1174 gravity = minorGravity; 1175 } 1176 1177 switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) { 1178 case Gravity.TOP: 1179 childTop = paddingTop + lp.topMargin; 1180 if (childBaseline != -1) { 1181 childTop += maxAscent[INDEX_TOP] - childBaseline; 1182 } 1183 break; 1184 1185 case Gravity.CENTER_VERTICAL: 1186 // Removed support for baseline alignment when layout_gravity or 1187 // gravity == center_vertical. See bug #1038483. 1188 // Keep the code around if we need to re-enable this feature 1189 // if (childBaseline != -1) { 1190 // // Align baselines vertically only if the child is smaller than us 1191 // if (childSpace - childHeight > 0) { 1192 // childTop = paddingTop + (childSpace / 2) - childBaseline; 1193 // } else { 1194 // childTop = paddingTop + (childSpace - childHeight) / 2; 1195 // } 1196 // } else { 1197 childTop = paddingTop + ((childSpace - childHeight) / 2) 1198 + lp.topMargin - lp.bottomMargin; 1199 break; 1200 1201 case Gravity.BOTTOM: 1202 childTop = childBottom - childHeight - lp.bottomMargin; 1203 if (childBaseline != -1) { 1204 int descent = child.getMeasuredHeight() - childBaseline; 1205 childTop -= (maxDescent[INDEX_BOTTOM] - descent); 1206 } 1207 break; 1208 default: 1209 childTop = paddingTop; 1210 break; 1211 } 1212 1213 childLeft += lp.leftMargin; 1214 setChildFrame(child, childLeft + getLocationOffset(child), childTop, 1215 childWidth, childHeight); 1216 childLeft += childWidth + lp.rightMargin + 1217 getNextLocationOffset(child); 1218 1219 i += getChildrenSkipCount(child, i); 1220 } 1221 } 1222 } 1223 1224 private void setChildFrame(View child, int left, int top, int width, int height) { 1225 child.layout(left, top, left + width, top + height); 1226 } 1227 1228 /** 1229 * Should the layout be a column or a row. 1230 * @param orientation Pass HORIZONTAL or VERTICAL. Default 1231 * value is HORIZONTAL. 1232 * 1233 * @attr ref android.R.styleable#LinearLayout_orientation 1234 */ 1235 public void setOrientation(int orientation) { 1236 if (mOrientation != orientation) { 1237 mOrientation = orientation; 1238 requestLayout(); 1239 } 1240 } 1241 1242 /** 1243 * Returns the current orientation. 1244 * 1245 * @return either {@link #HORIZONTAL} or {@link #VERTICAL} 1246 */ 1247 public int getOrientation() { 1248 return mOrientation; 1249 } 1250 1251 /** 1252 * Describes how the child views are positioned. Defaults to GRAVITY_TOP. If 1253 * this layout has a VERTICAL orientation, this controls where all the child 1254 * views are placed if there is extra vertical space. If this layout has a 1255 * HORIZONTAL orientation, this controls the alignment of the children. 1256 * 1257 * @param gravity See {@link android.view.Gravity} 1258 * 1259 * @attr ref android.R.styleable#LinearLayout_gravity 1260 */ 1261 @android.view.RemotableViewMethod 1262 public void setGravity(int gravity) { 1263 if (mGravity != gravity) { 1264 if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) { 1265 gravity |= Gravity.LEFT; 1266 } 1267 1268 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 1269 gravity |= Gravity.TOP; 1270 } 1271 1272 mGravity = gravity; 1273 requestLayout(); 1274 } 1275 } 1276 1277 @android.view.RemotableViewMethod 1278 public void setHorizontalGravity(int horizontalGravity) { 1279 final int gravity = horizontalGravity & Gravity.HORIZONTAL_GRAVITY_MASK; 1280 if ((mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != gravity) { 1281 mGravity = (mGravity & ~Gravity.HORIZONTAL_GRAVITY_MASK) | gravity; 1282 requestLayout(); 1283 } 1284 } 1285 1286 @android.view.RemotableViewMethod 1287 public void setVerticalGravity(int verticalGravity) { 1288 final int gravity = verticalGravity & Gravity.VERTICAL_GRAVITY_MASK; 1289 if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != gravity) { 1290 mGravity = (mGravity & ~Gravity.VERTICAL_GRAVITY_MASK) | gravity; 1291 requestLayout(); 1292 } 1293 } 1294 1295 @Override 1296 public LayoutParams generateLayoutParams(AttributeSet attrs) { 1297 return new LinearLayout.LayoutParams(getContext(), attrs); 1298 } 1299 1300 /** 1301 * Returns a set of layout parameters with a width of 1302 * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT} 1303 * and a height of {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} 1304 * when the layout's orientation is {@link #VERTICAL}. When the orientation is 1305 * {@link #HORIZONTAL}, the width is set to {@link LayoutParams#WRAP_CONTENT} 1306 * and the height to {@link LayoutParams#WRAP_CONTENT}. 1307 */ 1308 @Override 1309 protected LayoutParams generateDefaultLayoutParams() { 1310 if (mOrientation == HORIZONTAL) { 1311 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 1312 } else if (mOrientation == VERTICAL) { 1313 return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 1314 } 1315 return null; 1316 } 1317 1318 @Override 1319 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 1320 return new LayoutParams(p); 1321 } 1322 1323 1324 // Override to allow type-checking of LayoutParams. 1325 @Override 1326 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 1327 return p instanceof LinearLayout.LayoutParams; 1328 } 1329 1330 /** 1331 * Per-child layout information associated with ViewLinearLayout. 1332 * 1333 * @attr ref android.R.styleable#LinearLayout_Layout_layout_weight 1334 * @attr ref android.R.styleable#LinearLayout_Layout_layout_gravity 1335 */ 1336 public static class LayoutParams extends ViewGroup.MarginLayoutParams { 1337 /** 1338 * Indicates how much of the extra space in the LinearLayout will be 1339 * allocated to the view associated with these LayoutParams. Specify 1340 * 0 if the view should not be stretched. Otherwise the extra pixels 1341 * will be pro-rated among all views whose weight is greater than 0. 1342 */ 1343 @ViewDebug.ExportedProperty 1344 public float weight; 1345 1346 /** 1347 * Gravity for the view associated with these LayoutParams. 1348 * 1349 * @see android.view.Gravity 1350 */ 1351 @ViewDebug.ExportedProperty(mapping = { 1352 @ViewDebug.IntToString(from = -1, to = "NONE"), 1353 @ViewDebug.IntToString(from = Gravity.NO_GRAVITY, to = "NONE"), 1354 @ViewDebug.IntToString(from = Gravity.TOP, to = "TOP"), 1355 @ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"), 1356 @ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"), 1357 @ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"), 1358 @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"), 1359 @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"), 1360 @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"), 1361 @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL, to = "FILL_HORIZONTAL"), 1362 @ViewDebug.IntToString(from = Gravity.CENTER, to = "CENTER"), 1363 @ViewDebug.IntToString(from = Gravity.FILL, to = "FILL") 1364 }) 1365 public int gravity = -1; 1366 1367 /** 1368 * {@inheritDoc} 1369 */ 1370 public LayoutParams(Context c, AttributeSet attrs) { 1371 super(c, attrs); 1372 TypedArray a = 1373 c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout_Layout); 1374 1375 weight = a.getFloat(com.android.internal.R.styleable.LinearLayout_Layout_layout_weight, 0); 1376 gravity = a.getInt(com.android.internal.R.styleable.LinearLayout_Layout_layout_gravity, -1); 1377 1378 a.recycle(); 1379 } 1380 1381 /** 1382 * {@inheritDoc} 1383 */ 1384 public LayoutParams(int width, int height) { 1385 super(width, height); 1386 weight = 0; 1387 } 1388 1389 /** 1390 * Creates a new set of layout parameters with the specified width, height 1391 * and weight. 1392 * 1393 * @param width the width, either {@link #MATCH_PARENT}, 1394 * {@link #WRAP_CONTENT} or a fixed size in pixels 1395 * @param height the height, either {@link #MATCH_PARENT}, 1396 * {@link #WRAP_CONTENT} or a fixed size in pixels 1397 * @param weight the weight 1398 */ 1399 public LayoutParams(int width, int height, float weight) { 1400 super(width, height); 1401 this.weight = weight; 1402 } 1403 1404 /** 1405 * {@inheritDoc} 1406 */ 1407 public LayoutParams(ViewGroup.LayoutParams p) { 1408 super(p); 1409 } 1410 1411 /** 1412 * {@inheritDoc} 1413 */ 1414 public LayoutParams(MarginLayoutParams source) { 1415 super(source); 1416 } 1417 1418 @Override 1419 public String debug(String output) { 1420 return output + "LinearLayout.LayoutParams={width=" + sizeToString(width) + 1421 ", height=" + sizeToString(height) + " weight=" + weight + "}"; 1422 } 1423 } 1424} 1425