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