Skip to content

Commit 48793dd

Browse files
committed
Implement horizontal scrolling (scroll along the main axis) (#315)
This PR makes it available to let RecyclerView with FlexboxLayoutManager scroll along the main axis if the width of the RecyclerView is larger than its parent. (E.g. When the RecyclerView width is set to 800dp while the parent width is 500dp) This wasn't possible even wrap the RecyclerView with HorizontalScrollView because in that case, the widthMeasureSpec is sent as <width_of_parent> | View.MeasureSpec.UNSPECIFIED, thus the wrapping doesn't happen regardless of the size of the flex line being processed.
1 parent c1873e1 commit 48793dd

File tree

4 files changed

+229
-16
lines changed

4 files changed

+229
-16
lines changed

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

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3497,6 +3497,94 @@ public void run() {
34973497
assertThat((String) adapter.getPayloads().get(0), is(payload));
34983498
}
34993499

3500+
@Test
3501+
@FlakyTest
3502+
public void testScrollAlongManAxis_direction_row() throws Throwable {
3503+
// This test verifies the scroll along the main axis if the width of the RecyclerView is
3504+
// larger than its parent when the main axis direction is horizontal (row)
3505+
final FlexboxTestActivity activity = mActivityRule.getActivity();
3506+
final FlexboxLayoutManager layoutManager = new FlexboxLayoutManager(activity);
3507+
final TestAdapter adapter = new TestAdapter();
3508+
mActivityRule.runOnUiThread(new Runnable() {
3509+
@Override
3510+
public void run() {
3511+
activity.setContentView(R.layout.wrapped_recyclerview);
3512+
RecyclerView recyclerView = (RecyclerView) activity.findViewById(R.id.recyclerview);
3513+
layoutManager.setFlexDirection(FlexDirection.ROW);
3514+
recyclerView.setLayoutManager(layoutManager);
3515+
recyclerView.setAdapter(adapter);
3516+
for (int i = 0; i < 50; i++) {
3517+
FlexboxLayoutManager.LayoutParams lp = createLayoutParams(activity, 100, 70);
3518+
adapter.addItem(lp);
3519+
}
3520+
}
3521+
});
3522+
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
3523+
assertThat(layoutManager.getChildAt(0).getLeft(), is(0));
3524+
onView(withId(R.id.container)).perform(swipe(GeneralLocation.CENTER_RIGHT,
3525+
GeneralLocation.CENTER_LEFT));
3526+
onView(withId(R.id.container)).perform(swipe(GeneralLocation.CENTER_RIGHT,
3527+
GeneralLocation.CENTER_LEFT));
3528+
onView(withId(R.id.container)).perform(swipe(GeneralLocation.CENTER_RIGHT,
3529+
GeneralLocation.CENTER_LEFT));
3530+
assertThat(layoutManager.getChildAt(0).getLeft(), is(not(0)));
3531+
3532+
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
3533+
onView(withId(R.id.container)).perform(swipe(GeneralLocation.CENTER_LEFT,
3534+
GeneralLocation.CENTER_RIGHT));
3535+
onView(withId(R.id.container)).perform(swipe(GeneralLocation.CENTER_LEFT,
3536+
GeneralLocation.CENTER_RIGHT));
3537+
onView(withId(R.id.container)).perform(swipe(GeneralLocation.CENTER_LEFT,
3538+
GeneralLocation.CENTER_RIGHT));
3539+
onView(withId(R.id.container)).perform(swipe(GeneralLocation.CENTER_LEFT,
3540+
GeneralLocation.CENTER_RIGHT));
3541+
assertThat(layoutManager.getChildAt(0).getLeft(), is(0));
3542+
}
3543+
3544+
@Test
3545+
@FlakyTest
3546+
public void testScrollAlongManAxis_direction_column() throws Throwable {
3547+
// This test verifies the scroll along the main axis if the height of the RecyclerView is
3548+
// larger than its parent when the main axis direction is vertical (column).
3549+
final FlexboxTestActivity activity = mActivityRule.getActivity();
3550+
final FlexboxLayoutManager layoutManager = new FlexboxLayoutManager(activity);
3551+
final TestAdapter adapter = new TestAdapter();
3552+
mActivityRule.runOnUiThread(new Runnable() {
3553+
@Override
3554+
public void run() {
3555+
activity.setContentView(R.layout.wrapped_recyclerview_scroll_vertical);
3556+
RecyclerView recyclerView = (RecyclerView) activity.findViewById(R.id.recyclerview);
3557+
layoutManager.setFlexDirection(FlexDirection.COLUMN);
3558+
recyclerView.setLayoutManager(layoutManager);
3559+
recyclerView.setAdapter(adapter);
3560+
for (int i = 0; i < 50; i++) {
3561+
FlexboxLayoutManager.LayoutParams lp = createLayoutParams(activity, 70, 100);
3562+
adapter.addItem(lp);
3563+
}
3564+
}
3565+
});
3566+
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
3567+
assertThat(layoutManager.getChildAt(0).getTop(), is(0));
3568+
onView(withId(R.id.container)).perform(swipe(GeneralLocation.BOTTOM_CENTER,
3569+
GeneralLocation.TOP_CENTER));
3570+
onView(withId(R.id.container)).perform(swipe(GeneralLocation.BOTTOM_CENTER,
3571+
GeneralLocation.TOP_CENTER));
3572+
onView(withId(R.id.container)).perform(swipe(GeneralLocation.BOTTOM_CENTER,
3573+
GeneralLocation.TOP_CENTER));
3574+
assertThat(layoutManager.getChildAt(0).getTop(), is(not(0)));
3575+
3576+
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
3577+
onView(withId(R.id.container)).perform(swipe(GeneralLocation.TOP_CENTER,
3578+
GeneralLocation.BOTTOM_CENTER));
3579+
onView(withId(R.id.container)).perform(swipe(GeneralLocation.TOP_CENTER,
3580+
GeneralLocation.BOTTOM_CENTER));
3581+
onView(withId(R.id.container)).perform(swipe(GeneralLocation.TOP_CENTER,
3582+
GeneralLocation.BOTTOM_CENTER));
3583+
onView(withId(R.id.container)).perform(swipe(GeneralLocation.TOP_CENTER,
3584+
GeneralLocation.BOTTOM_CENTER));
3585+
assertThat(layoutManager.getChildAt(0).getTop(), is(0));
3586+
}
3587+
35003588
/**
35013589
* Creates a new flex item.
35023590
*
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" encoding="utf-8"?><!--
2+
~ Copyright 2017 Google Inc. All rights reserved.
3+
~
4+
~ Licensed under the Apache License, Version 2.0 (the "License");
5+
~ you may not use this file except in compliance with the License.
6+
~ You may obtain a copy of the License at
7+
~
8+
~ http://www.apache.org/licenses/LICENSE-2.0
9+
~
10+
~ Unless required by applicable law or agreed to in writing, software
11+
~ distributed under the License is distributed on an "AS IS" BASIS,
12+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
~ See the License for the specific language governing permissions and
14+
~ limitations under the License.
15+
-->
16+
<!-- Some APIs in espresso requires the view being performed is at least 90% visible to the
17+
user, using the small width so that low resolution devices are covered-->
18+
<FrameLayout android:id="@+id/container"
19+
xmlns:android="http://schemas.android.com/apk/res/android"
20+
android:layout_width="320dp"
21+
android:layout_height="240dp">
22+
<android.support.v7.widget.RecyclerView android:id="@+id/recyclerview"
23+
android:layout_width="600dp"
24+
android:layout_height="match_parent"/>
25+
</FrameLayout>
26+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" encoding="utf-8"?><!--
2+
~ Copyright 2017 Google Inc. All rights reserved.
3+
~
4+
~ Licensed under the Apache License, Version 2.0 (the "License");
5+
~ you may not use this file except in compliance with the License.
6+
~ You may obtain a copy of the License at
7+
~
8+
~ http://www.apache.org/licenses/LICENSE-2.0
9+
~
10+
~ Unless required by applicable law or agreed to in writing, software
11+
~ distributed under the License is distributed on an "AS IS" BASIS,
12+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
~ See the License for the specific language governing permissions and
14+
~ limitations under the License.
15+
-->
16+
<!-- Some APIs in espresso requires the view being performed is at least 90% visible to the
17+
user, using the small width so that low resolution devices are covered-->
18+
<FrameLayout android:id="@+id/container"
19+
xmlns:android="http://schemas.android.com/apk/res/android"
20+
android:layout_width="320dp"
21+
android:layout_height="240dp">
22+
<android.support.v7.widget.RecyclerView android:id="@+id/recyclerview"
23+
android:layout_width="match_parent"
24+
android:layout_height="600dp"/>
25+
</FrameLayout>
26+

0 commit comments

Comments
 (0)