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