Skip to content

Commit 5398c1f

Browse files
devvitferrannp
authored andcommitted
feat: Android VerticalPager (#70)
* android vertical scroll * keep support v4 with upstream repo * fix typo, remove needless * tap-stop-tapup-continue * make transformer and gesture for vertical only
1 parent 313e703 commit 5398c1f

File tree

3 files changed

+123
-1
lines changed

3 files changed

+123
-1
lines changed

android/src/main/java/com/reactnativecommunity/viewpager/ReactViewPager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
* views to custom {@link PagerAdapter} instance which is used by {@link NativeViewHierarchyManager}
2727
* to add children nodes according to react views hierarchy.
2828
*/
29-
public class ReactViewPager extends ViewPager {
29+
public class ReactViewPager extends VerticalViewPager {
3030

3131
private class Adapter extends PagerAdapter {
3232

android/src/main/java/com/reactnativecommunity/viewpager/ReactViewPagerManager.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ public void setScrollEnabled(ReactViewPager viewPager, boolean value) {
4646
viewPager.setScrollEnabled(value);
4747
}
4848

49+
@ReactProp(name = "orientation")
50+
public void setOrientation(ReactViewPager viewPager, String value) {
51+
viewPager.setOrientation(value.equals("vertical"));
52+
}
53+
4954
@Override
5055
public boolean needsCustomLayoutForChildren() {
5156
return true;
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package com.reactnativecommunity.viewpager;
2+
3+
import android.content.Context;
4+
import android.util.AttributeSet;
5+
import android.view.GestureDetector;
6+
import android.view.MotionEvent;
7+
import android.view.View;
8+
9+
import androidx.viewpager.widget.ViewPager;
10+
11+
// Vertical ViewPager implement, original code from
12+
// https://android.googlesource.com/platform/packages/apps/DeskClock/+/master/src/com/android/deskclock/VerticalViewPager.java
13+
public class VerticalViewPager extends ViewPager {
14+
private boolean mVertical = false;
15+
private GestureDetector mGestureDetector;
16+
17+
public VerticalViewPager(Context context) {
18+
super(context);
19+
}
20+
21+
public void setOrientation(boolean vertical) {
22+
mVertical = vertical;
23+
if (!mVertical) return;
24+
25+
// Make page transit vertical
26+
setPageTransformer(true, new VerticalPageTransformer());
27+
28+
// Nested scroll issue, follow the link
29+
// https://stackoverflow.com/questions/46828920/vertical-viewpager-with-horizontalscrollview-inside-fragment
30+
mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
31+
@Override
32+
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
33+
return Math.abs(distanceY) > Math.abs(distanceX);
34+
}
35+
});
36+
}
37+
38+
/**
39+
* @return {@code false} since a vertical view pager can never be scrolled horizontally
40+
*/
41+
@Override
42+
public boolean canScrollHorizontally(int direction) {
43+
return !canScrollVertically(direction);
44+
}
45+
46+
/**
47+
* @return {@code true} if a normal view pager would support horizontal scrolling at this time
48+
*/
49+
@Override
50+
public boolean canScrollVertically(int direction) {
51+
return mVertical;
52+
}
53+
54+
@Override
55+
public boolean onInterceptTouchEvent(MotionEvent ev) {
56+
boolean result = super.onInterceptTouchEvent(flipXY(ev));
57+
// Return MotionEvent to normal
58+
flipXY(ev);
59+
60+
if (mVertical) {
61+
if (mGestureDetector.onTouchEvent(ev)) {
62+
result = true;
63+
}
64+
}
65+
66+
return result;
67+
}
68+
69+
@Override
70+
public boolean onTouchEvent(MotionEvent ev) {
71+
boolean result = super.onTouchEvent(flipXY(ev));
72+
// Return MotionEvent to normal
73+
flipXY(ev);
74+
75+
if (mVertical) {
76+
if (mGestureDetector.onTouchEvent(ev)) {
77+
result = true;
78+
}
79+
}
80+
81+
return result;
82+
}
83+
84+
private MotionEvent flipXY(MotionEvent ev) {
85+
if (mVertical) {
86+
final float width = getWidth();
87+
final float height = getHeight();
88+
final float x = (ev.getY() / height) * width;
89+
final float y = (ev.getX() / width) * height;
90+
ev.setLocation(x, y);
91+
}
92+
return ev;
93+
}
94+
95+
private static final class VerticalPageTransformer implements ViewPager.PageTransformer {
96+
@Override
97+
public void transformPage(View view, float position) {
98+
final int pageWidth = view.getWidth();
99+
final int pageHeight = view.getHeight();
100+
if (position < -1) {
101+
// This page is way off-screen to the left.
102+
view.setAlpha(0);
103+
} else if (position <= 1) {
104+
view.setAlpha(1);
105+
// Counteract the default slide transition
106+
view.setTranslationX(pageWidth * -position);
107+
// set Y position to swipe in from top
108+
float yPosition = position * pageHeight;
109+
view.setTranslationY(yPosition);
110+
} else {
111+
// This page is way off-screen to the right.
112+
view.setAlpha(0);
113+
}
114+
}
115+
}
116+
}
117+

0 commit comments

Comments
 (0)