提交 a8c8b6e5 编写于 作者: A Alessandro Balocco 提交者: Takeshi Hagikura

Take CompoundButtons drawables min size into account during measurements (#528)

CompoundButtons such as Checkboxes, when are allowed to shrink (flexShrink = 1f), during the recalculation can end up being shrunk more than what I would consider their "minimum size" since the negative space is calculated for all FlexItems in the shrinkFlexItems() method.

In this PR I try to prevent these components to get completely shrunk by considering the minimum size of their button drawable. In this way, the drawable size will determine the minimum size of the widget unless a minWidth or minHeight are specified by the user.
上级 9f9d07dd
......@@ -17,6 +17,7 @@
package com.google.android.flexbox
import android.view.View
import android.widget.CheckBox
import android.widget.TextView
import androidx.test.rule.ActivityTestRule
import androidx.test.runner.AndroidJUnit4
......@@ -399,6 +400,74 @@ class FlexboxHelperTest {
assertThat(view3.measuredWidth, `is`(100))
}
@Test
@Throws(Throwable::class)
fun testDetermineMainSize_directionRow_considerCompoundButtonImplicitMinSizeWhenNotSpecified() {
val containerWidth = 500
val activity = activityRule.activity
val lp1 = FlexboxLayout.LayoutParams(
FlexboxLayout.LayoutParams.WRAP_CONTENT,
FlexboxLayout.LayoutParams.WRAP_CONTENT)
val view1 = CheckBox(activity)
view1.layoutParams = lp1
val lp2 = FlexboxLayout.LayoutParams(
FlexboxLayout.LayoutParams.WRAP_CONTENT,
FlexboxLayout.LayoutParams.WRAP_CONTENT)
val view2 = TextView(activity)
view2.layoutParams = lp2
view2.text = LONG_TEXT
flexContainer.addView(view1)
flexContainer.addView(view2)
flexContainer.flexWrap = FlexWrap.NOWRAP
val widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(containerWidth, View.MeasureSpec.AT_MOST)
val heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.UNSPECIFIED)
val result = FlexboxHelper.FlexLinesResult()
flexboxHelper.calculateHorizontalFlexLines(result, widthMeasureSpec, heightMeasureSpec)
flexContainer.flexLines = result.mFlexLines
flexboxHelper.determineMainSize(widthMeasureSpec, heightMeasureSpec)
// CompoundButton will use its ButtonDrawable minWidth to determine its size when
// no minimum width is set on it.
val drawableMinWidth = view1.buttonDrawable!!.minimumWidth
val expectedTextWidth = containerWidth - drawableMinWidth
assertThat(view1.measuredWidth, `is`(drawableMinWidth))
assertThat(view2.measuredWidth, `is`(expectedTextWidth))
}
@Test
@Throws(Throwable::class)
fun testDetermineMainSize_directionRow_considerCompoundButtonExplicitMinSizeWhenSpecified() {
val containerWidth = 500
val compoundButtonMinWidth = 150
val activity = activityRule.activity
val lp1 = FlexboxLayout.LayoutParams(
FlexboxLayout.LayoutParams.WRAP_CONTENT,
FlexboxLayout.LayoutParams.WRAP_CONTENT)
lp1.minWidth = compoundButtonMinWidth
val view1 = CheckBox(activity)
view1.layoutParams = lp1
val lp2 = FlexboxLayout.LayoutParams(
FlexboxLayout.LayoutParams.WRAP_CONTENT,
FlexboxLayout.LayoutParams.WRAP_CONTENT)
val view2 = TextView(activity)
view2.layoutParams = lp2
view2.text = LONG_TEXT
flexContainer.addView(view1)
flexContainer.addView(view2)
flexContainer.flexWrap = FlexWrap.NOWRAP
val widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(containerWidth, View.MeasureSpec.AT_MOST)
val heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.UNSPECIFIED)
val result = FlexboxHelper.FlexLinesResult()
flexboxHelper.calculateHorizontalFlexLines(result, widthMeasureSpec, heightMeasureSpec)
flexContainer.flexLines = result.mFlexLines
flexboxHelper.determineMainSize(widthMeasureSpec, heightMeasureSpec)
// CompoundButton will be measured based on its explicitly specified minWidth.
val expectedTextWidth = containerWidth - compoundButtonMinWidth
assertThat(view1.measuredWidth, `is`(compoundButtonMinWidth))
assertThat(view2.measuredWidth, `is`(expectedTextWidth))
}
@Test
@Throws(Throwable::class)
fun testDetermineCrossSize_direction_row_alignContent_stretch() {
......
......@@ -19,14 +19,15 @@ package com.google.android.flexbox;
import static com.google.android.flexbox.FlexContainer.NOT_SET;
import static com.google.android.flexbox.FlexItem.FLEX_BASIS_PERCENT_DEFAULT;
import static com.google.android.flexbox.FlexItem.FLEX_GROW_DEFAULT;
import static com.google.android.flexbox.FlexItem.FLEX_SHRINK_DEFAULT;
import static com.google.android.flexbox.FlexItem.FLEX_SHRINK_NOT_SET;
import static androidx.recyclerview.widget.RecyclerView.NO_POSITION;
import android.graphics.drawable.Drawable;
import android.util.SparseIntArray;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import java.util.ArrayList;
import java.util.Arrays;
......@@ -37,6 +38,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.view.MarginLayoutParamsCompat;
import androidx.core.widget.CompoundButtonCompat;
/**
* Offers various calculations for Flexbox to use the common logic between the classes such as
......@@ -438,6 +440,8 @@ class FlexboxHelper {
addFlexLine(flexLines, flexLine, i, sumCrossSize);
}
continue;
} else if (child instanceof CompoundButton) {
evaluateMinimumSizeForCompoundButton((CompoundButton) child);
}
FlexItem flexItem = (FlexItem) child.getLayoutParams();
......@@ -628,6 +632,28 @@ class FlexboxHelper {
result.mChildState = childState;
}
/**
* Compound buttons (ex. {{@link android.widget.CheckBox}}, {@link android.widget.ToggleButton})
* have a button drawable with minimum height and width specified for them.
* To align the behavior with CSS Flexbox we want to respect these minimum measurement to avoid
* these drawables from being cut off during calculation. When the compound button has a minimum
* width or height already specified we will not make any change since we assume those were
* voluntarily set by the user.
*
* @param compoundButton the compound button that need to be evaluated
*/
private void evaluateMinimumSizeForCompoundButton(CompoundButton compoundButton) {
FlexItem flexItem = (FlexItem) compoundButton.getLayoutParams();
int minWidth = flexItem.getMinWidth();
int minHeight = flexItem.getMinHeight();
Drawable drawable = CompoundButtonCompat.getButtonDrawable(compoundButton);
int drawableMinWidth = drawable == null ? 0 : drawable.getMinimumWidth();
int drawableMinHeight = drawable == null ? 0 : drawable.getMinimumHeight();
flexItem.setMinWidth(minWidth == NOT_SET ? drawableMinWidth : minWidth);
flexItem.setMinHeight(minHeight == NOT_SET ? drawableMinHeight : minHeight);
}
/**
* Returns the container's start padding in the main axis. Either start or top.
*
......
......@@ -1598,12 +1598,12 @@ public class FlexboxLayout extends ViewGroup implements FlexContainer {
/**
* @see FlexItem#getMinWidth()
*/
private int mMinWidth;
private int mMinWidth = NOT_SET;
/**
* @see FlexItem#getMinHeight()
*/
private int mMinHeight;
private int mMinHeight = NOT_SET;
/**
* @see FlexItem#getMaxWidth()
......@@ -1636,9 +1636,9 @@ public class FlexboxLayout extends ViewGroup implements FlexContainer {
.getFraction(R.styleable.FlexboxLayout_Layout_layout_flexBasisPercent, 1, 1,
FLEX_BASIS_PERCENT_DEFAULT);
mMinWidth = a
.getDimensionPixelSize(R.styleable.FlexboxLayout_Layout_layout_minWidth, 0);
.getDimensionPixelSize(R.styleable.FlexboxLayout_Layout_layout_minWidth, NOT_SET);
mMinHeight = a
.getDimensionPixelSize(R.styleable.FlexboxLayout_Layout_layout_minHeight, 0);
.getDimensionPixelSize(R.styleable.FlexboxLayout_Layout_layout_minHeight, NOT_SET);
mMaxWidth = a.getDimensionPixelSize(R.styleable.FlexboxLayout_Layout_layout_maxWidth,
MAX_SIZE);
mMaxHeight = a.getDimensionPixelSize(R.styleable.FlexboxLayout_Layout_layout_maxHeight,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册