Skip to content

Commit bf320b4

Browse files
authored
Add max line attribute to specify the maximum number of flex lines. (#424)
Add maxLine support from the XML
1 parent decddb9 commit bf320b4

File tree

8 files changed

+123
-2
lines changed

8 files changed

+123
-2
lines changed

flexbox/src/androidTest/java/com/google/android/flexbox/FakeFlexContainer.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package com.google.android.flexbox
1818

1919
import android.view.View
2020
import android.view.ViewGroup
21+
import com.google.android.flexbox.FlexContainer.NOT_SET
2122

2223
/**
2324
* Fake implementation of [FlexContainer].
@@ -43,6 +44,8 @@ internal class FakeFlexContainer : FlexContainer {
4344
@AlignContent
4445
private var alignContent = AlignContent.STRETCH
4546

47+
private var maxLine = -1
48+
4649
override fun getFlexItemCount() = views.size
4750

4851
override fun getFlexItemAt(index: Int) = views[index]
@@ -95,6 +98,12 @@ internal class FakeFlexContainer : FlexContainer {
9598
this.alignItems = alignItems
9699
}
97100

101+
override fun getMaxLine(): Int = this.maxLine
102+
103+
override fun setMaxLine(maxLine: Int) {
104+
this.maxLine = maxLine
105+
}
106+
98107
override fun getFlexLines() = flexLines
99108

100109
override fun isMainAxisDirectionHorizontal(): Boolean {

flexbox/src/androidTest/java/com/google/android/flexbox/test/FlexboxAndroidTest.kt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3967,6 +3967,28 @@ class FlexboxAndroidTest {
39673967
assertThat(view2.right, `is`(240))
39683968
}
39693969

3970+
@Test
3971+
@FlakyTest
3972+
@Throws(Throwable::class)
3973+
fun testMaxLines() {
3974+
val activity = activityRule.activity
3975+
val flexboxLayout = createFlexboxLayout(R.layout.activity_empty_children,
3976+
object : Configuration {
3977+
override fun apply(flexboxLayout: FlexboxLayout) {
3978+
flexboxLayout.maxLine = 3
3979+
for (i in 1..50) {
3980+
val textView = createTextView(activity, i.toString(), 0)
3981+
val lp = FlexboxLayout.LayoutParams(100, 100)
3982+
lp.flexShrink = 0f
3983+
textView.layoutParams = lp
3984+
flexboxLayout.addView(textView)
3985+
}
3986+
}
3987+
})
3988+
assertThat(flexboxLayout.childCount, `is`(50))
3989+
assertThat(flexboxLayout.flexLines.size, `is`(3))
3990+
}
3991+
39703992
@Throws(Throwable::class)
39713993
private fun createFlexboxLayout(@LayoutRes activityLayoutResId: Int,
39723994
configuration: Configuration = Configuration.EMPTY): FlexboxLayout {

flexbox/src/androidTest/java/com/google/android/flexbox/test/FlexboxLayoutManagerTest.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3310,6 +3310,30 @@ class FlexboxLayoutManagerTest {
33103310
assertThat(layoutManager.getChildAt(0).top, `is`(0))
33113311
}
33123312

3313+
@Test
3314+
@FlakyTest
3315+
@Throws(Throwable::class)
3316+
fun testMaxLine() {
3317+
val activity = activityRule.activity
3318+
val layoutManager = FlexboxLayoutManager(activity)
3319+
val adapter = TestAdapter()
3320+
activityRule.runOnUiThread {
3321+
activity.setContentView(R.layout.recyclerview)
3322+
val recyclerView = activity.findViewById<RecyclerView>(R.id.recyclerview)
3323+
layoutManager.flexDirection = FlexDirection.ROW
3324+
layoutManager.maxLine = 3
3325+
recyclerView.layoutManager = layoutManager
3326+
recyclerView.adapter = adapter
3327+
for (i in 1..50) {
3328+
val lp = createLayoutParams(activity, 100, 70)
3329+
lp.flexShrink = 0f
3330+
adapter.addItem(lp)
3331+
}
3332+
}
3333+
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
3334+
assertThat(layoutManager.flexLines.size, `is`(3))
3335+
}
3336+
33133337
/**
33143338
* Creates a new flex item.
33153339
*

flexbox/src/main/java/com/google/android/flexbox/FlexContainer.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
*/
2727
interface FlexContainer {
2828

29+
int NOT_SET = -1;
30+
2931
/**
3032
* @return the number of flex items contained in the flex container.
3133
*/
@@ -270,6 +272,18 @@ interface FlexContainer {
270272
*/
271273
void setFlexLines(List<FlexLine> flexLines);
272274

275+
/**
276+
* @return the current value of the maximum number of flex lines. If not set, {@link #NOT_SET}
277+
* is returned.
278+
*/
279+
int getMaxLine();
280+
281+
/**
282+
*
283+
* @param maxLine the int value, which specifies the maximum number of flex lines
284+
*/
285+
void setMaxLine(int maxLine);
286+
273287
/**
274288
* @return the list of the flex lines including dummy flex lines (flex line that doesn't have
275289
* any flex items in it but used for the alignment along the cross axis), which aren't included

flexbox/src/main/java/com/google/android/flexbox/FlexboxHelper.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import static android.support.v7.widget.RecyclerView.NO_POSITION;
2020

21+
import static com.google.android.flexbox.FlexContainer.NOT_SET;
2122
import static com.google.android.flexbox.FlexItem.FLEX_BASIS_PERCENT_DEFAULT;
2223

2324
import android.support.annotation.NonNull;
@@ -498,7 +499,7 @@ void calculateFlexLines(FlexLinesResult result, int mainMeasureSpec,
498499
getViewMeasuredSizeMain(child, isMainHorizontal)
499500
+ getFlexItemMarginStartMain(flexItem, isMainHorizontal) +
500501
getFlexItemMarginEndMain(flexItem, isMainHorizontal),
501-
flexItem, i, indexInFlexLine)) {
502+
flexItem, i, indexInFlexLine, flexLines.size())) {
502503
if (flexLine.getItemCountNotGone() > 0) {
503504
addFlexLine(flexLines, flexLine, i > 0 ? i - 1 : 0, sumCrossSize);
504505
sumCrossSize += flexLine.mCrossSize;
@@ -823,12 +824,15 @@ private int getFlexItemMarginEndCross(FlexItem flexItem, boolean isMainHorizonta
823824
* @param childLength the length of a child view which is to be collected to the flex line
824825
* @param flexItem the LayoutParams for the view being determined whether a new flex line
825826
* is needed
827+
* @param index the index of the view being added within the entire flex container
828+
* @param indexInFlexLine the index of the view being added within the current flex line
829+
* @param flexLinesSize the number of the existing flexlines size
826830
* @return {@code true} if a wrap is required, {@code false} otherwise
827831
* @see FlexContainer#getFlexWrap()
828832
* @see FlexContainer#setFlexWrap(int)
829833
*/
830834
private boolean isWrapRequired(View view, int mode, int maxSize, int currentLength,
831-
int childLength, FlexItem flexItem, int index, int indexInFlexLine) {
835+
int childLength, FlexItem flexItem, int index, int indexInFlexLine, int flexLinesSize) {
832836
if (mFlexContainer.getFlexWrap() == FlexWrap.NOWRAP) {
833837
return false;
834838
}
@@ -838,6 +842,12 @@ private boolean isWrapRequired(View view, int mode, int maxSize, int currentLeng
838842
if (mode == View.MeasureSpec.UNSPECIFIED) {
839843
return false;
840844
}
845+
int maxLine = mFlexContainer.getMaxLine();
846+
// Judge the condition by adding 1 to the current flexLinesSize because the flex line
847+
// being computed isn't added to the flexLinesSize.
848+
if (maxLine != NOT_SET && maxLine <= flexLinesSize + 1) {
849+
return false;
850+
}
841851
int decorationLength =
842852
mFlexContainer.getDecorationLengthMainAxis(view, index, indexInFlexLine);
843853
if (decorationLength > 0) {

flexbox/src/main/java/com/google/android/flexbox/FlexboxLayout.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
* <li>{@code dividerDrawable}</li>
5757
* <li>{@code dividerDrawableHorizontal}</li>
5858
* <li>{@code dividerDrawableVertical}</li>
59+
* <li>{@code maxLine}</li>
5960
* </ul>
6061
* for the FlexboxLayout.
6162
*
@@ -114,6 +115,11 @@ public class FlexboxLayout extends ViewGroup implements FlexContainer {
114115
*/
115116
private int mAlignContent;
116117

118+
/**
119+
* The current value of the {@link }
120+
*/
121+
private int mMaxLine = NOT_SET;
122+
117123
/**
118124
* The int definition to be used as the arguments for the {@link #setShowDivider(int)},
119125
* {@link #setShowDividerHorizontal(int)} or {@link #setShowDividerVertical(int)}.
@@ -218,6 +224,7 @@ public FlexboxLayout(Context context, AttributeSet attrs, int defStyleAttr) {
218224
.getInt(R.styleable.FlexboxLayout_justifyContent, JustifyContent.FLEX_START);
219225
mAlignItems = a.getInt(R.styleable.FlexboxLayout_alignItems, AlignItems.STRETCH);
220226
mAlignContent = a.getInt(R.styleable.FlexboxLayout_alignContent, AlignContent.STRETCH);
227+
mMaxLine = a.getInt(R.styleable.FlexboxLayout_maxLine, NOT_SET);
221228
Drawable drawable = a.getDrawable(R.styleable.FlexboxLayout_dividerDrawable);
222229
if (drawable != null) {
223230
setDividerDrawableHorizontal(drawable);
@@ -1205,6 +1212,19 @@ public void setAlignContent(@AlignContent int alignContent) {
12051212
}
12061213
}
12071214

1215+
@Override
1216+
public int getMaxLine() {
1217+
return mMaxLine;
1218+
}
1219+
1220+
@Override
1221+
public void setMaxLine(int maxLine) {
1222+
if (mMaxLine != maxLine) {
1223+
mMaxLine = maxLine;
1224+
requestLayout();
1225+
}
1226+
}
1227+
12081228
/**
12091229
* @return the flex lines composing this flex container. This method returns a copy of the
12101230
* original list excluding a dummy flex line (flex line that doesn't have any flex items in it

flexbox/src/main/java/com/google/android/flexbox/FlexboxLayoutManager.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ public class FlexboxLayoutManager extends RecyclerView.LayoutManager implements
8888
*/
8989
private int mAlignItems;
9090

91+
private int mMaxLine = NOT_SET;
92+
9193
/**
9294
* True if the layout direction is right to left, false otherwise.
9395
*/
@@ -353,6 +355,19 @@ public void setAlignContent(@AlignContent int alignContent) {
353355
+ "if you need to use this attribute.");
354356
}
355357

358+
@Override
359+
public int getMaxLine() {
360+
return mMaxLine;
361+
}
362+
363+
@Override
364+
public void setMaxLine(int maxLine) {
365+
if (mMaxLine != maxLine) {
366+
mMaxLine = maxLine;
367+
requestLayout();
368+
}
369+
}
370+
356371
@Override
357372
public List<FlexLine> getFlexLines() {
358373
List<FlexLine> result = new ArrayList<>(mFlexLines.size());

flexbox/src/main/res/values/attrs.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ limitations under the License.
8282
<flag name="middle" value="2" />
8383
<flag name="end" value="4" />
8484
</attr>
85+
86+
<!--
87+
The attribute that specifies the maximum number of flex lines. This attribute is
88+
effective only when the flexWrap attribute is "wrap" or "wrap_reverse".
89+
-->
90+
<attr name="maxLine" format="integer" />
91+
8592
</declare-styleable>
8693

8794
<declare-styleable name="FlexboxLayout_Layout">

0 commit comments

Comments
 (0)