提交 196afa85 编写于 作者: T Takeshi Hagikura

Addresses my review comments based on evant's PR

https://github.com/google/flexbox-layout/pull/34

Change-Id: I0fdeff297e66a5310fe692175b0db737f10b12c6
上级 b2051603
......@@ -64,8 +64,10 @@ public class FlexItem implements Parcelable {
public float flexBasisPercent;
/** Minimum with in DP */
public int minWidth;
/** Minimum height in DP */
public int minHeight;
public FlexItem() {
......@@ -132,8 +134,8 @@ public class FlexItem implements Parcelable {
MarginLayoutParamsCompat.setMarginStart(lp, startMargin);
MarginLayoutParamsCompat.setMarginEnd(lp, endMargin);
lp.bottomMargin = bottomMargin;
lp.minWidth = minWidth;
lp.minHeight = minHeight;
lp.minWidth = Util.dpToPixel(context, minWidth);
lp.minHeight = Util.dpToPixel(context, minHeight);
return lp;
}
......@@ -156,8 +158,8 @@ public class FlexItem implements Parcelable {
flexItem.paddingStart = ViewCompat.getPaddingStart(view);
flexItem.paddingEnd = ViewCompat.getPaddingEnd(view);
flexItem.paddingBottom = view.getPaddingBottom();
flexItem.minWidth = lp.minWidth;
flexItem.minHeight = lp.minHeight;
flexItem.minWidth = Util.pixelToDp(view.getContext(), lp.minWidth);
flexItem.minHeight = Util.pixelToDp(view.getContext(), lp.minHeight);
return flexItem;
}
......
......@@ -218,7 +218,8 @@ public class FlexItemEditFragment extends DialogFragment {
public void onClick(View v) {
if (orderTextInput.isErrorEnabled() || flexGrowInput.isErrorEnabled() ||
flexBasisPercentInput.isErrorEnabled() || widthInput.isErrorEnabled() ||
heightInput.isErrorEnabled()) {
heightInput.isErrorEnabled() || minWidthInput.isErrorEnabled() ||
minHeightInput.isErrorEnabled()) {
Toast.makeText(getActivity(), R.string.invalid_values_exist, Toast.LENGTH_SHORT)
.show();
return;
......
......@@ -104,7 +104,7 @@ limitations under the License.
<string name="hint_min_height">Min Height</string>
<string name="must_be_non_negative_float">Must be a non-negative float value</string>
<string name="must_be_non_negative_integer">Must a non-negative integer value</string>
<string name="must_be_non_negative_integer">Must be a non-negative integer value</string>
<string name="must_be_minus_one_or_minus_two_or_non_negative_integer">Must be -1 or -2 or a non-negative integer value</string>
<string name="must_be_integer">Must be an integer value</string>
<string name="must_be_minus_one_or_non_negative_integer">Must be -1 or a non-negative integer value</string>
......
......@@ -47,6 +47,7 @@ import static android.support.test.espresso.assertion.PositionAssertions.isRight
import static android.support.test.espresso.assertion.PositionAssertions.isRightOf;
import static android.support.test.espresso.assertion.PositionAssertions.isTopAlignedWith;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNot.not;
......@@ -698,7 +699,8 @@ public class FlexboxAndroidTest {
// Both the parent FrameLayout and the FlexboxLayout have different padding values
// but the text3.getRight should be the padding value for the FlexboxLayout, not including
// the parent's padding value
assertThat(flexboxLayout.getWidth() - text3.getRight(), is(flexboxLayout.getPaddingRight()));
assertThat(flexboxLayout.getWidth() - text3.getRight(),
is(flexboxLayout.getPaddingRight()));
assertThat(text3.getTop(), is(flexboxLayout.getPaddingTop()));
}
......@@ -2452,7 +2454,7 @@ public class FlexboxAndroidTest {
@Test
@FlakyTest(tolerance = TOLERANCE)
public void testMinWidth() throws Throwable {
public void testMinWidth_initial_width_less_than_minWidth() throws Throwable {
final FlexboxTestActivity activity = mActivityRule.getActivity();
mActivityRule.runOnUiThread(new Runnable() {
@Override
......@@ -2461,6 +2463,10 @@ public class FlexboxAndroidTest {
}
});
// This test case verifies if the minWidth attribute works as a minimum constraint
// If the initial view width is less than the value of minWidth.
// The textView1's layout_width is set to wrap_content and its text is "1" apparently
// the initial measured width is less than the value of layout_minWidth (100dp)
FlexboxLayout flexboxLayout = (FlexboxLayout) activity.findViewById(R.id.flexbox_layout);
TextView textView1 = (TextView) activity.findViewById(R.id.text1);
int minWidth = ((FlexboxLayout.LayoutParams) textView1.getLayoutParams()).minWidth;
......@@ -2471,7 +2477,33 @@ public class FlexboxAndroidTest {
@Test
@FlakyTest(tolerance = TOLERANCE)
public void testMinHeight() throws Throwable {
public void testMinWidth_works_as_lower_bound_shrink_to() throws Throwable {
final FlexboxTestActivity activity = mActivityRule.getActivity();
mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
activity.setContentView(R.layout.activity_minwidth_lower_bound_test);
}
});
// This test case verifies if the minWidth attribute works as a lower bound
// when the view would shrink less than the minWidth if the minWidth weren't set
FlexboxLayout flexboxLayout = (FlexboxLayout) activity.findViewById(R.id.flexbox_layout);
TextView textView1 = (TextView) activity.findViewById(R.id.text1);
TextView textView2 = (TextView) activity.findViewById(R.id.text2);
TextView textView3 = (TextView) activity.findViewById(R.id.text3);
TextView textView4 = (TextView) activity.findViewById(R.id.text4);
int minWidth = ((FlexboxLayout.LayoutParams) textView1.getLayoutParams()).minWidth;
onView(withId(R.id.text1)).check(hasWidth(minWidth));
assertEquals(flexboxLayout.getWidth(),
textView1.getWidth() + textView2.getWidth() + textView3.getWidth() + textView4
.getWidth());
}
@Test
@FlakyTest(tolerance = TOLERANCE)
public void testMinHeight_initial_height_less_than_minHeight() throws Throwable {
final FlexboxTestActivity activity = mActivityRule.getActivity();
mActivityRule.runOnUiThread(new Runnable() {
@Override
......@@ -2480,6 +2512,10 @@ public class FlexboxAndroidTest {
}
});
// This test case verifies if the minHeight attribute works as a minimum constraint
// If the initial view height is less than the value of minHeight.
// The textView1's layout_height is set to wrap_content and its text is "1" apparently
// the initial measured height is less than the value of layout_minHeight (100dp)
FlexboxLayout flexboxLayout = (FlexboxLayout) activity.findViewById(R.id.flexbox_layout);
TextView textView1 = (TextView) activity.findViewById(R.id.text1);
int minHeight = ((FlexboxLayout.LayoutParams) textView1.getLayoutParams()).minHeight;
......@@ -2488,6 +2524,32 @@ public class FlexboxAndroidTest {
onView(withId(R.id.text2)).check(hasHeight(flexboxLayout.getHeight() - minHeight));
}
@Test
@FlakyTest(tolerance = TOLERANCE)
public void testMinHeight_works_as_lower_bound_shrink_to() throws Throwable {
final FlexboxTestActivity activity = mActivityRule.getActivity();
mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
activity.setContentView(R.layout.activity_minheight_lower_bound_test);
}
});
// This test case verifies if the minHeight attribute works as a lower bound
// when the view would shrink less than the minHeight if the minHeight weren't set
FlexboxLayout flexboxLayout = (FlexboxLayout) activity.findViewById(R.id.flexbox_layout);
TextView textView1 = (TextView) activity.findViewById(R.id.text1);
TextView textView2 = (TextView) activity.findViewById(R.id.text2);
TextView textView3 = (TextView) activity.findViewById(R.id.text3);
TextView textView4 = (TextView) activity.findViewById(R.id.text4);
int minHeight = ((FlexboxLayout.LayoutParams) textView1.getLayoutParams()).minHeight;
onView(withId(R.id.text1)).check(hasHeight(minHeight));
assertEquals(flexboxLayout.getHeight(),
textView1.getHeight() + textView2.getHeight() + textView3.getHeight()
+ textView4.getHeight());
}
@Test
@FlakyTest(tolerance = TOLERANCE)
public void testView_visibility_gone() throws Throwable {
......
<?xml version="1.0" encoding="utf-8"?><!--
Copyright 2016 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<com.google.android.flexbox.FlexboxLayout android:id="@+id/flexbox_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="400dp"
android:layout_height="400dp"
app:flexDirection="column"
app:flexWrap="nowrap" >
<TextView
android:id="@+id/text1"
android:layout_width="wrap_content"
android:layout_height="200dp"
android:text="1"
app:layout_minHeight="150dp" />
<TextView
android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="200dp"
android:text="2" />
<TextView
android:id="@+id/text3"
android:layout_width="wrap_content"
android:layout_height="200dp"
android:text="3" />
<TextView
android:id="@+id/text4"
android:layout_width="wrap_content"
android:layout_height="200dp"
android:text="4" />
</com.google.android.flexbox.FlexboxLayout>
\ No newline at end of file
......@@ -17,16 +17,15 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="400dp"
android:layout_height="match_parent"
android:layout_height="400dp"
app:flexDirection="column">
<TextView
android:id="@+id/text1"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_height="wrap_content"
android:text="1"
app:layout_flexGrow="1"
app:layout_minHeight="300dp" />
app:layout_minHeight="100dp" />
<TextView
android:id="@+id/text2"
......
<?xml version="1.0" encoding="utf-8"?><!--
Copyright 2016 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<com.google.android.flexbox.FlexboxLayout android:id="@+id/flexbox_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="400dp"
android:layout_height="400dp"
app:flexWrap="nowrap" >
<TextView
android:id="@+id/text1"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:text="1"
app:layout_minWidth="150dp" />
<TextView
android:id="@+id/text2"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:text="2" />
<TextView
android:id="@+id/text3"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:text="3" />
<TextView
android:id="@+id/text4"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:text="4" />
</com.google.android.flexbox.FlexboxLayout>
\ No newline at end of file
......@@ -16,16 +16,15 @@
<com.google.android.flexbox.FlexboxLayout android:id="@+id/flexbox_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_width="400dp"
android:layout_height="400dp">
<TextView
android:id="@+id/text1"
android:layout_width="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"
app:layout_flexGrow="1"
app:layout_minWidth="300dp" />
app:layout_minWidth="100dp" />
<TextView
android:id="@+id/text2"
......
......@@ -223,10 +223,10 @@ public class FlexboxLayout extends ViewGroup {
/**
* Holds the 'frozen' state of children during measure. If a view is frozen it will no longer
* expand or shrink regardless of flexGrow/flexShrink. Items are indexed by the child's
* expand or shrink regardless of flexGrow/flexShrink. Items are indexed by the child's
* reordered index.
*/
private boolean[] mFrozenChildren;
private boolean[] mChildrenFrozen;
public FlexboxLayout(Context context) {
this(context, null);
......@@ -256,7 +256,9 @@ public class FlexboxLayout extends ViewGroup {
if (isOrderChangedFromLastMeasurement()) {
mReorderedIndices = createReorderedIndices();
}
mFrozenChildren = new boolean[getChildCount()];
// TODO: Move the object allocation to other methods instead of onMeasure
mChildrenFrozen = new boolean[getChildCount()];
// TODO: Only calculate the children views which are affected from the last measure.
switch (mFlexDirection) {
......@@ -469,6 +471,16 @@ public class FlexboxLayout extends ViewGroup {
getPaddingTop() + getPaddingBottom() + lp.topMargin
+ lp.bottomMargin, lp.height);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
// Check the minimum constraint after the first measurement for the child
// To prevent the child's width becomes less than the value of minWidth
// E.g. When the child's layout_width is wrap_content the measured width may be
// less than the min width after the first measurement.
if (child.getMeasuredWidth() < lp.minWidth) {
child.measure(MeasureSpec.makeMeasureSpec(lp.minWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(),
MeasureSpec.EXACTLY));
}
childState = ViewCompat
.combineMeasuredStates(childState, ViewCompat.getMeasuredState(child));
largestHeightInRow = Math.max(largestHeightInRow,
......@@ -612,6 +624,16 @@ public class FlexboxLayout extends ViewGroup {
getPaddingTop() + getPaddingBottom() + lp.topMargin
+ lp.bottomMargin, childHeight);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
// Check the minimum constraint after the first measurement for the child
// To prevent the child's height becomes less than the value of minHeight
// E.g. When the child's layout_height is wrap_content the measured height may be
// less than the min height after the first measurement.
if (child.getMeasuredHeight() < lp.minHeight) {
child.measure(
MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(lp.minHeight, MeasureSpec.EXACTLY));
}
childState = ViewCompat
.combineMeasuredStates(childState, ViewCompat.getMeasuredState(child));
largestWidthInColumn = Math.max(largestWidthInColumn,
......@@ -726,91 +748,64 @@ public class FlexboxLayout extends ViewGroup {
*/
private int expandFlexItems(FlexLine flexLine, @FlexDirection int flexDirection,
int maxMainSize, int paddingAlongMainAxis, int startIndex) {
int childIndex = startIndex;
int sizeBeforeExpand = flexLine.mainSize;
if (flexLine.totalFlexGrow <= 0 || maxMainSize < flexLine.mainSize) {
childIndex += flexLine.itemCount;
return childIndex;
startIndex += flexLine.itemCount;
return startIndex;
}
boolean needsReshrink = false;
float unitSpace = (maxMainSize - flexLine.mainSize) / flexLine.totalFlexGrow;
flexLine.mainSize = paddingAlongMainAxis;
float accumulatedRoundError = 0;
for (int i = 0; i < flexLine.itemCount; i++) {
View child = getReorderedChildAt(childIndex);
View child = getReorderedChildAt(startIndex);
if (child == null) {
continue;
} else if (child.getVisibility() == View.GONE) {
childIndex++;
startIndex++;
continue;
}
LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (flexDirection == FLEX_DIRECTION_ROW
|| flexDirection == FLEX_DIRECTION_ROW_REVERSE) {
if (!mFrozenChildren[childIndex]) {
float rawCalculatedWidth = child.getMeasuredWidth() + unitSpace * lp.flexGrow;
if (i == flexLine.itemCount - 1) {
rawCalculatedWidth += accumulatedRoundError;
accumulatedRoundError = 0;
}
int newWidth = Math.round(rawCalculatedWidth);
if (newWidth < lp.minWidth) {
needsReshrink = true;
newWidth = lp.minWidth;
mFrozenChildren[childIndex] = true;
flexLine.totalFlexShrink -= lp.flexShrink;
} else {
accumulatedRoundError += (rawCalculatedWidth - newWidth);
if (accumulatedRoundError > 1.0) {
newWidth += 1;
accumulatedRoundError -= 1.0;
} else if (accumulatedRoundError < -1.0) {
newWidth -= 1;
accumulatedRoundError += 1.0;
}
}
child.measure(MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY),
MeasureSpec
.makeMeasureSpec(child.getMeasuredHeight(),
MeasureSpec.EXACTLY));
float rawCalculatedWidth = child.getMeasuredWidth() + unitSpace * lp.flexGrow;
if (i == flexLine.itemCount - 1) {
rawCalculatedWidth += accumulatedRoundError;
accumulatedRoundError = 0;
}
int newWidth = Math.round(rawCalculatedWidth);
accumulatedRoundError += (rawCalculatedWidth - newWidth);
if (accumulatedRoundError > 1.0) {
newWidth += 1;
accumulatedRoundError -= 1.0;
} else if (accumulatedRoundError < -1.0) {
newWidth -= 1;
accumulatedRoundError += 1.0;
}
child.measure(MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY),
MeasureSpec
.makeMeasureSpec(child.getMeasuredHeight(),
MeasureSpec.EXACTLY));
flexLine.mainSize += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
} else {
if (!mFrozenChildren[childIndex]) {
float rawCalculatedHeight = child.getMeasuredHeight() + unitSpace * lp.flexGrow;
if (i == flexLine.itemCount - 1) {
rawCalculatedHeight += accumulatedRoundError;
accumulatedRoundError = 0;
}
int newHeight = Math.round(rawCalculatedHeight);
if (newHeight < lp.minHeight) {
needsReshrink = true;
newHeight = lp.minHeight;
mFrozenChildren[childIndex] = true;
flexLine.totalFlexShrink -= lp.flexShrink;
} else {
accumulatedRoundError += (rawCalculatedHeight - newHeight);
if (accumulatedRoundError > 1.0) {
newHeight += 1;
accumulatedRoundError -= 1.0;
} else if (accumulatedRoundError < -1.0) {
newHeight -= 1;
accumulatedRoundError += 1.0;
}
}
child.measure(MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(),
MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY));
float rawCalculatedHeight = child.getMeasuredHeight() + unitSpace * lp.flexGrow;
if (i == flexLine.itemCount - 1) {
rawCalculatedHeight += accumulatedRoundError;
accumulatedRoundError = 0;
}
int newHeight = Math.round(rawCalculatedHeight);
accumulatedRoundError += (rawCalculatedHeight - newHeight);
if (accumulatedRoundError > 1.0) {
newHeight += 1;
accumulatedRoundError -= 1.0;
} else if (accumulatedRoundError < -1.0) {
newHeight -= 1;
accumulatedRoundError += 1.0;
}
child.measure(MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(),
MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY));
flexLine.mainSize += child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
}
childIndex++;
}
if (needsReshrink && sizeBeforeExpand != flexLine.mainSize) {
// After expanding we may have negative free space if some of the items were clamped to
// a min size.
shrinkFlexItems(flexLine, flexDirection, maxMainSize, paddingAlongMainAxis, startIndex);
startIndex++;
}
return startIndex;
}
......@@ -854,8 +849,10 @@ public class FlexboxLayout extends ViewGroup {
LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (flexDirection == FLEX_DIRECTION_ROW
|| flexDirection == FLEX_DIRECTION_ROW_REVERSE) {
if (!mFrozenChildren[childIndex]) {
float rawCalculatedWidth = child.getMeasuredWidth() - unitShrink * lp.flexShrink;
// The direction of main axis is horizontal
if (!mChildrenFrozen[childIndex]) {
float rawCalculatedWidth = child.getMeasuredWidth()
- unitShrink * lp.flexShrink;
if (i == flexLine.itemCount - 1) {
rawCalculatedWidth += accumulatedRoundError;
accumulatedRoundError = 0;
......@@ -869,7 +866,7 @@ public class FlexboxLayout extends ViewGroup {
// startIndex.
needsReshrink = true;
newWidth = lp.minWidth;
mFrozenChildren[childIndex] = true;
mChildrenFrozen[childIndex] = true;
flexLine.totalFlexShrink -= lp.flexShrink;
} else {
accumulatedRoundError += (rawCalculatedWidth - newWidth);
......@@ -882,14 +879,15 @@ public class FlexboxLayout extends ViewGroup {
}
}
child.measure(MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY),
MeasureSpec
.makeMeasureSpec(child.getMeasuredHeight(),
MeasureSpec.EXACTLY));
MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(),
MeasureSpec.EXACTLY));
}
flexLine.mainSize += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
} else {
if (!mFrozenChildren[childIndex]) {
float rawCalculatedHeight = child.getMeasuredHeight() - unitShrink * lp.flexShrink;
// The direction of main axis is vertical
if (!mChildrenFrozen[childIndex]) {
float rawCalculatedHeight = child.getMeasuredHeight()
- unitShrink * lp.flexShrink;
if (i == flexLine.itemCount - 1) {
rawCalculatedHeight += accumulatedRoundError;
accumulatedRoundError = 0;
......@@ -899,7 +897,7 @@ public class FlexboxLayout extends ViewGroup {
// Need to invoke this method again like the case flex direction is vertical
needsReshrink = true;
newHeight = lp.minHeight;
mFrozenChildren[childIndex] = true;
mChildrenFrozen[childIndex] = true;
flexLine.totalFlexShrink -= lp.flexShrink;
} else {
accumulatedRoundError += (rawCalculatedHeight - newHeight);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册