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