NestedScrollView and Horizontal RecyclerView Smooth Scrolling

后端 未结 3 1510
后悔当初
后悔当初 2020-12-08 05:00

I have a single vertical nestedscrollview that contains a bunch of recyclerview with a horizontal layoutmanager setup. The idea is pretty similar to how the new google play

3条回答
  •  一向
    一向 (楼主)
    2020-12-08 05:34

    So the smooth scrolling issue is fixed now. It was caused by a bug in the NestedScrollView in the Design Support Library (currently 23.1.1).

    You can read about the issue and the simple fix here: https://code.google.com/p/android/issues/detail?id=194398

    In short, after you performed a fling, the nestedscrollview didn't register a complete on the scroller component and so it needed an additional 'ACTION_DOWN' event to release the parent nestedscrollview from intercepting(eating up) the subsequent events. So what happened was if you tried scrolling your child list(or viewpager), after a fling, the first touch releases the parent NSV bind and the subsequent touches would work. That was making the UX really bad.

    Essentially need to add this line on the ACTION_DOWN event of the NSV:

    computeScroll();
    

    Here is what I'm using:

    public class MyNestedScrollView extends NestedScrollView {
    private int slop;
    private float mInitialMotionX;
    private float mInitialMotionY;
    
    public MyNestedScrollView(Context context) {
        super(context);
        init(context);
    }
    
    private void init(Context context) {
        ViewConfiguration config = ViewConfiguration.get(context);
        slop = config.getScaledEdgeSlop();
    }
    
    public MyNestedScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }
    
    public MyNestedScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }
    
    
    private float xDistance, yDistance, lastX, lastY;
    
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final float x = ev.getX();
        final float y = ev.getY();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                xDistance = yDistance = 0f;
                lastX = ev.getX();
                lastY = ev.getY();
    
                // This is very important line that fixes 
               computeScroll();
    
    
                break;
            case MotionEvent.ACTION_MOVE:
                final float curX = ev.getX();
                final float curY = ev.getY();
                xDistance += Math.abs(curX - lastX);
                yDistance += Math.abs(curY - lastY);
                lastX = curX;
                lastY = curY;
    
                if (xDistance > yDistance) {
                    return false;
                }
        }
    
    
        return super.onInterceptTouchEvent(ev);
    }
    

    }

    Use this class in place of your nestedscrollview in the xml file, and the child lists should intercept and handle the touch events properly.

    Phew, there are actually quite a few bugs like these that makes me want to ditch the design support library altogether and revisit it when its more mature.

提交回复
热议问题