From c0ba2835b3cb403bc38f115fa049641bf054505d Mon Sep 17 00:00:00 2001 From: Takeshi Hagikura Date: Mon, 14 May 2018 14:27:55 +0900 Subject: [PATCH] Add max line attribute to specify the maximum number of flex lines. Fixes #156 --- .../android/flexbox/FakeFlexContainer.kt | 9 +++++++ .../flexbox/test/FlexboxAndroidTest.kt | 22 +++++++++++++++++ .../flexbox/test/FlexboxLayoutManagerTest.kt | 24 +++++++++++++++++++ .../google/android/flexbox/FlexContainer.java | 14 +++++++++++ .../google/android/flexbox/FlexboxHelper.java | 14 +++++++++-- .../google/android/flexbox/FlexboxLayout.java | 18 ++++++++++++++ .../android/flexbox/FlexboxLayoutManager.java | 15 ++++++++++++ 7 files changed, 114 insertions(+), 2 deletions(-) diff --git a/flexbox/src/androidTest/java/com/google/android/flexbox/FakeFlexContainer.kt b/flexbox/src/androidTest/java/com/google/android/flexbox/FakeFlexContainer.kt index aec9bc56..cef644ce 100644 --- a/flexbox/src/androidTest/java/com/google/android/flexbox/FakeFlexContainer.kt +++ b/flexbox/src/androidTest/java/com/google/android/flexbox/FakeFlexContainer.kt @@ -18,6 +18,7 @@ package com.google.android.flexbox import android.view.View import android.view.ViewGroup +import com.google.android.flexbox.FlexContainer.NOT_SET /** * Fake implementation of [FlexContainer]. @@ -43,6 +44,8 @@ internal class FakeFlexContainer : FlexContainer { @AlignContent private var alignContent = AlignContent.STRETCH + private var maxLine = -1 + override fun getFlexItemCount() = views.size override fun getFlexItemAt(index: Int) = views[index] @@ -95,6 +98,12 @@ internal class FakeFlexContainer : FlexContainer { this.alignItems = alignItems } + override fun getMaxLine(): Int = this.maxLine + + override fun setMaxLine(maxLine: Int) { + this.maxLine = maxLine + } + override fun getFlexLines() = flexLines override fun isMainAxisDirectionHorizontal(): Boolean { diff --git a/flexbox/src/androidTest/java/com/google/android/flexbox/test/FlexboxAndroidTest.kt b/flexbox/src/androidTest/java/com/google/android/flexbox/test/FlexboxAndroidTest.kt index 8f2e29ab..7bcfcd78 100644 --- a/flexbox/src/androidTest/java/com/google/android/flexbox/test/FlexboxAndroidTest.kt +++ b/flexbox/src/androidTest/java/com/google/android/flexbox/test/FlexboxAndroidTest.kt @@ -3967,6 +3967,28 @@ class FlexboxAndroidTest { assertThat(view2.right, `is`(240)) } + @Test + @FlakyTest + @Throws(Throwable::class) + fun testMaxLines() { + val activity = activityRule.activity + val flexboxLayout = createFlexboxLayout(R.layout.activity_empty_children, + object : Configuration { + override fun apply(flexboxLayout: FlexboxLayout) { + flexboxLayout.maxLine = 3 + for (i in 1..50) { + val textView = createTextView(activity, i.toString(), 0) + val lp = FlexboxLayout.LayoutParams(100, 100) + lp.flexShrink = 0f + textView.layoutParams = lp + flexboxLayout.addView(textView) + } + } + }) + assertThat(flexboxLayout.childCount, `is`(50)) + assertThat(flexboxLayout.flexLines.size, `is`(3)) + } + @Throws(Throwable::class) private fun createFlexboxLayout(@LayoutRes activityLayoutResId: Int, configuration: Configuration = Configuration.EMPTY): FlexboxLayout { diff --git a/flexbox/src/androidTest/java/com/google/android/flexbox/test/FlexboxLayoutManagerTest.kt b/flexbox/src/androidTest/java/com/google/android/flexbox/test/FlexboxLayoutManagerTest.kt index ff295edf..76da7074 100644 --- a/flexbox/src/androidTest/java/com/google/android/flexbox/test/FlexboxLayoutManagerTest.kt +++ b/flexbox/src/androidTest/java/com/google/android/flexbox/test/FlexboxLayoutManagerTest.kt @@ -3310,6 +3310,30 @@ class FlexboxLayoutManagerTest { assertThat(layoutManager.getChildAt(0).top, `is`(0)) } + @Test + @FlakyTest + @Throws(Throwable::class) + fun testMaxLine() { + val activity = activityRule.activity + val layoutManager = FlexboxLayoutManager(activity) + val adapter = TestAdapter() + activityRule.runOnUiThread { + activity.setContentView(R.layout.recyclerview) + val recyclerView = activity.findViewById(R.id.recyclerview) + layoutManager.flexDirection = FlexDirection.ROW + layoutManager.maxLine = 3 + recyclerView.layoutManager = layoutManager + recyclerView.adapter = adapter + for (i in 1..50) { + val lp = createLayoutParams(activity, 100, 70) + lp.flexShrink = 0f + adapter.addItem(lp) + } + } + InstrumentationRegistry.getInstrumentation().waitForIdleSync() + assertThat(layoutManager.flexLines.size, `is`(3)) + } + /** * Creates a new flex item. * diff --git a/flexbox/src/main/java/com/google/android/flexbox/FlexContainer.java b/flexbox/src/main/java/com/google/android/flexbox/FlexContainer.java index 6708a27e..34211192 100644 --- a/flexbox/src/main/java/com/google/android/flexbox/FlexContainer.java +++ b/flexbox/src/main/java/com/google/android/flexbox/FlexContainer.java @@ -26,6 +26,8 @@ */ interface FlexContainer { + int NOT_SET = -1; + /** * @return the number of flex items contained in the flex container. */ @@ -270,6 +272,18 @@ interface FlexContainer { */ void setFlexLines(List flexLines); + /** + * @return the current value of the maximum number of flex lines. If not set, {@link #NOT_SET} + * is returned. + */ + int getMaxLine(); + + /** + * + * @param maxLine the int value, which specifies the maximum number of flex lines + */ + void setMaxLine(int maxLine); + /** * @return the list of the flex lines including dummy flex lines (flex line that doesn't have * any flex items in it but used for the alignment along the cross axis), which aren't included diff --git a/flexbox/src/main/java/com/google/android/flexbox/FlexboxHelper.java b/flexbox/src/main/java/com/google/android/flexbox/FlexboxHelper.java index 65e07317..f9996b5b 100644 --- a/flexbox/src/main/java/com/google/android/flexbox/FlexboxHelper.java +++ b/flexbox/src/main/java/com/google/android/flexbox/FlexboxHelper.java @@ -18,6 +18,7 @@ import static android.support.v7.widget.RecyclerView.NO_POSITION; +import static com.google.android.flexbox.FlexContainer.NOT_SET; import static com.google.android.flexbox.FlexItem.FLEX_BASIS_PERCENT_DEFAULT; import android.support.annotation.NonNull; @@ -498,7 +499,7 @@ void calculateFlexLines(FlexLinesResult result, int mainMeasureSpec, getViewMeasuredSizeMain(child, isMainHorizontal) + getFlexItemMarginStartMain(flexItem, isMainHorizontal) + getFlexItemMarginEndMain(flexItem, isMainHorizontal), - flexItem, i, indexInFlexLine)) { + flexItem, i, indexInFlexLine, flexLines.size())) { if (flexLine.getItemCountNotGone() > 0) { addFlexLine(flexLines, flexLine, i > 0 ? i - 1 : 0, sumCrossSize); sumCrossSize += flexLine.mCrossSize; @@ -823,12 +824,15 @@ private int getFlexItemMarginEndCross(FlexItem flexItem, boolean isMainHorizonta * @param childLength the length of a child view which is to be collected to the flex line * @param flexItem the LayoutParams for the view being determined whether a new flex line * is needed + * @param index the index of the view being added within the entire flex container + * @param indexInFlexLine the index of the view being added within the current flex line + * @param flexLinesSize the number of the existing flexlines size * @return {@code true} if a wrap is required, {@code false} otherwise * @see FlexContainer#getFlexWrap() * @see FlexContainer#setFlexWrap(int) */ private boolean isWrapRequired(View view, int mode, int maxSize, int currentLength, - int childLength, FlexItem flexItem, int index, int indexInFlexLine) { + int childLength, FlexItem flexItem, int index, int indexInFlexLine, int flexLinesSize) { if (mFlexContainer.getFlexWrap() == FlexWrap.NOWRAP) { return false; } @@ -838,6 +842,12 @@ private boolean isWrapRequired(View view, int mode, int maxSize, int currentLeng if (mode == View.MeasureSpec.UNSPECIFIED) { return false; } + int maxLine = mFlexContainer.getMaxLine(); + // Judge the condition by adding 1 to the current flexLinesSize because the flex line + // being computed isn't added to the flexLinesSize. + if (maxLine != NOT_SET && maxLine <= flexLinesSize + 1) { + return false; + } int decorationLength = mFlexContainer.getDecorationLengthMainAxis(view, index, indexInFlexLine); if (decorationLength > 0) { diff --git a/flexbox/src/main/java/com/google/android/flexbox/FlexboxLayout.java b/flexbox/src/main/java/com/google/android/flexbox/FlexboxLayout.java index fc895621..3969bf4e 100644 --- a/flexbox/src/main/java/com/google/android/flexbox/FlexboxLayout.java +++ b/flexbox/src/main/java/com/google/android/flexbox/FlexboxLayout.java @@ -114,6 +114,11 @@ public class FlexboxLayout extends ViewGroup implements FlexContainer { */ private int mAlignContent; + /** + * The current value of the {@link } + */ + private int mMaxLine = NOT_SET; + /** * The int definition to be used as the arguments for the {@link #setShowDivider(int)}, * {@link #setShowDividerHorizontal(int)} or {@link #setShowDividerVertical(int)}. @@ -1205,6 +1210,19 @@ public void setAlignContent(@AlignContent int alignContent) { } } + @Override + public int getMaxLine() { + return mMaxLine; + } + + @Override + public void setMaxLine(int maxLine) { + if (mMaxLine != maxLine) { + mMaxLine = maxLine; + requestLayout(); + } + } + /** * @return the flex lines composing this flex container. This method returns a copy of the * original list excluding a dummy flex line (flex line that doesn't have any flex items in it diff --git a/flexbox/src/main/java/com/google/android/flexbox/FlexboxLayoutManager.java b/flexbox/src/main/java/com/google/android/flexbox/FlexboxLayoutManager.java index 804dfcfa..49217e7c 100644 --- a/flexbox/src/main/java/com/google/android/flexbox/FlexboxLayoutManager.java +++ b/flexbox/src/main/java/com/google/android/flexbox/FlexboxLayoutManager.java @@ -88,6 +88,8 @@ public class FlexboxLayoutManager extends RecyclerView.LayoutManager implements */ private int mAlignItems; + private int mMaxLine = NOT_SET; + /** * True if the layout direction is right to left, false otherwise. */ @@ -353,6 +355,19 @@ public void setAlignContent(@AlignContent int alignContent) { + "if you need to use this attribute."); } + @Override + public int getMaxLine() { + return mMaxLine; + } + + @Override + public void setMaxLine(int maxLine) { + if (mMaxLine != maxLine) { + mMaxLine = maxLine; + requestLayout(); + } + } + @Override public List getFlexLines() { List result = new ArrayList<>(mFlexLines.size());