Add a new attribute to LinearLayout: useLargestChild.
Bug #2379138
This new attribute is to be used when the LinearLayout is wrap_content but you want
all the children inside to have the same dimension. Set useLargestChild to true and
give all the children a width/height of 0 and a weight of 1.0.
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 0ce70fa..5c78af5 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -94,6 +94,9 @@
@ViewDebug.ExportedProperty
private float mWeightSum;
+ @ViewDebug.ExportedProperty
+ private boolean mUseLargestChild;
+
private int[] mMaxAscent;
private int[] mMaxDescent;
@@ -102,7 +105,7 @@
private static final int INDEX_CENTER_VERTICAL = 0;
private static final int INDEX_TOP = 1;
private static final int INDEX_BOTTOM = 2;
- private static final int INDEX_FILL = 3;
+ private static final int INDEX_FILL = 3;
public LinearLayout(Context context) {
super(context);
@@ -134,6 +137,9 @@
mBaselineAlignedChildIndex =
a.getInt(com.android.internal.R.styleable.LinearLayout_baselineAlignedChildIndex, -1);
+ // TODO: Better name, add Java APIs, make it public
+ mUseLargestChild = a.getBoolean(R.styleable.LinearLayout_useLargestChild, false);
+
a.recycle();
}
@@ -328,6 +334,9 @@
boolean matchWidth = false;
final int baselineChildIndex = mBaselineAlignedChildIndex;
+ final boolean useLargestChild = mUseLargestChild;
+
+ int largestChildHeight = Integer.MIN_VALUE;
// See how tall everyone is. Also remember max width.
for (int i = 0; i < count; ++i) {
@@ -353,30 +362,35 @@
// there is any leftover space.
mTotalLength += lp.topMargin + lp.bottomMargin;
} else {
- int oldHeight = Integer.MIN_VALUE;
+ int oldHeight = Integer.MIN_VALUE;
- if (lp.height == 0 && lp.weight > 0) {
+ if (lp.height == 0 && lp.weight > 0) {
// heightMode is either UNSPECIFIED OR AT_MOST, and this child
// wanted to stretch to fill available space. Translate that to
// WRAP_CONTENT so that it does not end up with a height of 0
oldHeight = 0;
lp.height = LayoutParams.WRAP_CONTENT;
- }
+ }
- // Determine how big this child would like to. If this or
- // previous children have given a weight, then we allow it to
- // use all available space (and we will shrink things later
- // if needed).
- measureChildBeforeLayout(
+ // Determine how big this child would like to. If this or
+ // previous children have given a weight, then we allow it to
+ // use all available space (and we will shrink things later
+ // if needed).
+ measureChildBeforeLayout(
child, i, widthMeasureSpec, 0, heightMeasureSpec,
totalWeight == 0 ? mTotalLength : 0);
- if (oldHeight != Integer.MIN_VALUE) {
+ if (oldHeight != Integer.MIN_VALUE) {
lp.height = oldHeight;
- }
+ }
- mTotalLength += child.getMeasuredHeight() + lp.topMargin +
+ final int childHeight = child.getMeasuredHeight();
+ mTotalLength += childHeight + lp.topMargin +
lp.bottomMargin + getNextLocationOffset(child);
+
+ if (useLargestChild) {
+ largestChildHeight = Math.max(childHeight, largestChildHeight);
+ }
}
/**
@@ -426,7 +440,30 @@
i += getChildrenSkipCount(child, i);
}
-
+
+ if (useLargestChild) {
+ mTotalLength = 0;
+
+ for (int i = 0; i < count; ++i) {
+ final View child = getVirtualChildAt(i);
+
+ if (child == null) {
+ mTotalLength += measureNullChild(i);
+ continue;
+ }
+
+ if (child.getVisibility() == GONE) {
+ i += getChildrenSkipCount(child, i);
+ continue;
+ }
+
+ final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
+ child.getLayoutParams();
+ mTotalLength += largestChildHeight + lp.topMargin+ lp.bottomMargin +
+ getNextLocationOffset(child);
+ }
+ }
+
// Add in our padding
mTotalLength += mPaddingTop + mPaddingBottom;
@@ -587,6 +624,9 @@
maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;
final boolean baselineAligned = mBaselineAligned;
+ final boolean useLargestChild = mUseLargestChild;
+
+ int largestChildWidth = Integer.MIN_VALUE;
// See how wide everyone is. Also remember max height.
for (int i = 0; i < count; ++i) {
@@ -602,7 +642,8 @@
continue;
}
- final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
+ final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
+ child.getLayoutParams();
totalWeight += lp.weight;
@@ -643,9 +684,14 @@
if (oldWidth != Integer.MIN_VALUE) {
lp.width = oldWidth;
}
-
- mTotalLength += child.getMeasuredWidth() + lp.leftMargin +
- lp.rightMargin + getNextLocationOffset(child);
+
+ final int childWidth = child.getMeasuredWidth();
+ mTotalLength += childWidth + lp.leftMargin + lp.rightMargin +
+ getNextLocationOffset(child);
+
+ if (useLargestChild) {
+ largestChildWidth = Math.max(childWidth, largestChildWidth);
+ }
}
boolean matchHeightLocally = false;
@@ -708,6 +754,29 @@
maxHeight = Math.max(maxHeight, ascent + descent);
}
+ if (useLargestChild) {
+ mTotalLength = 0;
+
+ for (int i = 0; i < count; ++i) {
+ final View child = getVirtualChildAt(i);
+
+ if (child == null) {
+ mTotalLength += measureNullChild(i);
+ continue;
+ }
+
+ if (child.getVisibility() == GONE) {
+ i += getChildrenSkipCount(child, i);
+ continue;
+ }
+
+ final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
+ child.getLayoutParams();
+ mTotalLength += largestChildWidth + lp.leftMargin + lp.rightMargin +
+ getNextLocationOffset(child);
+ }
+ }
+
// Add in our padding
mTotalLength += mPaddingLeft + mPaddingRight;
@@ -953,7 +1022,7 @@
final int paddingLeft = mPaddingLeft;
int childTop = mPaddingTop;
- int childLeft = paddingLeft;
+ int childLeft;
// Where right end of child should go
final int width = mRight - mLeft;
@@ -1038,7 +1107,7 @@
void layoutHorizontal() {
final int paddingTop = mPaddingTop;
- int childTop = paddingTop;
+ int childTop;
int childLeft = mPaddingLeft;
// Where bottom of child should go
@@ -1103,7 +1172,7 @@
break;
case Gravity.CENTER_VERTICAL:
- // Removed support for baselign alignment when layout_gravity or
+ // Removed support for baseline alignment when layout_gravity or
// gravity == center_vertical. See bug #1038483.
// Keep the code around if we need to re-enable this feature
// if (childBaseline != -1) {
diff --git a/core/res/res/layout/alert_dialog.xml b/core/res/res/layout/alert_dialog.xml
index 409dcd3..4a63c5b 100644
--- a/core/res/res/layout/alert_dialog.xml
+++ b/core/res/res/layout/alert_dialog.xml
@@ -109,7 +109,8 @@
android:orientation="horizontal"
android:paddingTop="4dip"
android:paddingLeft="2dip"
- android:paddingRight="2dip" >
+ android:paddingRight="2dip"
+ android:useLargestChild="true">
<LinearLayout android:id="@+id/leftSpacer"
android:layout_weight="0.25"
android:layout_width="0dip"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8dadd88..140ab09 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1700,6 +1700,10 @@
space by giving it a layout_weight of 0.5 and setting the weightSum
to 1.0. -->
<attr name="weightSum" format="float" />
+ <!-- When set to true, all children with a weight will be considered having
+ the minimum size of the largest child. If false, all children are
+ measured normally. -->
+ <attr name="useLargestChild" format="boolean" />
</declare-styleable>
<declare-styleable name="ListView">
<!-- Reference to an array resource that will populate the ListView. For static content,