React-native-pager-view: Vertical Android ViewPager not working on Android 9 (Pie)

Created on 1 Dec 2019  路  15Comments  路  Source: callstack/react-native-pager-view

Swiping for a short distance and fast should change the page. This is working fine in my Pixel 2 (Android 10) and in Android the emulator. However, we tried a couple of devices where is not working correctly:

  • Samsung Galaxy Note 9 (Android 9)
  • Xiaomi MI MIX 2 (Android 9)

This is the behavior on for the vertical ViewPager:

vertical

Basically the user needs to scroll all the way down or up (manually) to trigger a change of page. With the horizontal ViewPager (recorded on the same phone), it works just as expected:

horizontal

Would love to get some help from you @devvit if you know what might be causing this.

bug Help Wanted

Most helpful comment

Or I'll fork the internal code here (it will not change anyway as they are with ViewPager2 now). I'll prepare a PR.

All 15 comments

@ferrannp, What about this ?
I haven't these devices, only tested on my 5 devices(4.4 - 9.0) :(

Thanks for the reference @devvit! I'll be trying it tomorrow.

Mmm for now still that did not really help @devvit. That just seems to play with the threshold the page needs to be moved to swipe... But I think the problem here is different. If you drag very small distance but fast (with power), it should swipe to the next page. Still investigating... By the way, I was able to reproduce it on an emulator (Note 9 Android 9) using https://developer.samsung.com/remotetestlab/. The only drawback is that every time you want to try something you need to build the production apk.

Ok, I can reproduce the issue with the Android emulator (good to find a solution) on API level 28 (Android P). It seems to work before and after but not on Android P (most popular nowadays).

@ferrannp, Make ViewPager snap with shorter drag

My reflection solution, you can change the value of mMinimumVelocity and mFlingDistance.

    public void setOrientation(boolean vertical) {
        mVertical = vertical;
        if (!mVertical) return;

        // Make page transit vertical
        setPageTransformer(true, new VerticalPageTransformer());

        // Nested scroll issue, follow the link
        // https://stackoverflow.com/questions/46828920/vertical-viewpager-with-horizontalscrollview-inside-fragment
        mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                return Math.abs(distanceY) > Math.abs(distanceX);
            }
        });

        // reflection
        try {
            Field mFlingDistance = ViewPager.class.getDeclaredField("mFlingDistance");
            mFlingDistance.setAccessible(true);
            mFlingDistance.setInt(this, 10);

            Field mMinimumVelocity = ViewPager.class.getDeclaredField("mMinimumVelocity");
            mMinimumVelocity.setAccessible(true);
            mMinimumVelocity.setInt(this, 5);
        } catch (Exception e) {
            Log.e("###", e.getMessage());
        }
    }

Could you try straya's answer? I'm not sure that.

@devvit I found a a perfect working solution modifying the source code. https://android.googlesource.com/platform/frameworks/support/+/5b614a46f6ffb3e9ca5ab6321c12412550a4e13a/viewpager/src/main/java/androidx/viewpager/widget/ViewPager.java#2251. Instead of getXVelocity, if pager is vertical would be getYVelocity.

Can we achieve this by reflection without copying the whole source code?

Looks impossible 馃槗, just change mMinimumVelocity.
Or maybe we commit a PR to android master dev 馃槄

Or I'll fork the internal code here (it will not change anyway as they are with ViewPager2 now). I'll prepare a PR.

Yes, fork it, freeze it, until we migrate to VP2

@troZee @ferrannp Is there any workaround to use vertical ViewPager now? I was so excited about native feel viewpager on react native, but found out that it's broken on Android...馃樋

PS: Thanks for working on it!

@todorone or you can create patch-package of #139. I need to fix one thing.
Ofc I am not guarantee, that it will work, but you can try.

PS: Thanks for working on it!

<3

@troZee @ferrannp Thanks for prompt feedback, you guys are awesome.

Just tried both fix/vertical-pager-android-9-bug branch and also viewpager2 branch. Both of them didn't help, I still need to swipe with finger for a almost full height distance to make vertical transition happen. Checked on both horizontal and vertical device alignment, Android 9 Mi 5 Note device(Emulator with Android 10 works perfectly)...

@todorone you can use a custom hook to handle touch events by yourself like below:

// the hook
import React, {useState} from 'react';
function TouchGesture(ref) {
  const [duration, setDuration] = useState(0);
  const [points, setPoints] = useState([0, 0]);
  function onTouchStart(e) {
    const {pageX, pageY} = e.nativeEvent;
    setDuration(Date.now());
    setPoints([pageX, pageY]);
  }
  function onTouchEnd(e) {
    const {pageX, pageY} = e.nativeEvent;
    if (Date.now() - duration > 200 || Math.abs(points[0] - pageX) > 50) {
      return;
    }
   // this just an example
   // you can use viewPager's position (add a onPageSelected function there) to judge which page you'll set; 
    if (points[1] - pageY > 30) {
      ref?.current.setPage(1);
    } else if (pageY - points[1] > 30) {
      ref?.current.setPage(0);
    }
  }
  return {onTouchEnd, onTouchStart};
}
export default TouchGesture;


// usage
const viewPagerRef = useRef(null);
const {onTouchEnd, onTouchStart} = useTouchGesture(viewPagerRef);
 const handleTouchEnd = useCallback(e => onTouchEnd(e), [onTouchEnd]);
const handleTouchStart = useCallback(e => onTouchStart(e), [onTouchStart]);
......
<ViewPager
      ref={viewPagerRef}
      scrollEnabled={false}
      orientation="vertical"
      pageMargin={0}
      onTouchStart={handleTouchStart}
      onTouchEnd={handleTouchEnd}
      style={styles.viewPager}
      initialPage={0}>
    ......
</ViewPager>
Was this page helpful?
0 / 5 - 0 ratings

Related issues

hengkx picture hengkx  路  8Comments

ivan3177 picture ivan3177  路  6Comments

iqbalfaisal picture iqbalfaisal  路  3Comments

ivan3177 picture ivan3177  路  6Comments

stefan-girlich picture stefan-girlich  路  9Comments