NestedRecyclerView icon indicating copy to clipboard operation
NestedRecyclerView copied to clipboard

有两个问题

Open 1181631922 opened this issue 5 years ago • 5 comments

rt 1.向上滑动列表时初次滑动会有卡顿问题 2.当下方Recyclerview全部显示的时候,在快速fling的过程中,底部Recyclerview在未全部显示(滑动到顶部时)就已经将手势交给外层列表开始滑动头部Recyclerview

1181631922 avatar Aug 20 '20 16:08 1181631922

第一个是因为创建新视图的原因,可以放在子线程。 第二个是因为父控件的onInterceptTouchEvent拦截出的问题,定位原因在Recyclerview里面 // Clear the active onInterceptTouchListener. None should be set at this time, and if one // is, it's because some other code didn't follow the standard contract. mInterceptingOnItemTouchListener = null; if (findInterceptingOnItemTouchListener(e)) { cancelScroll(); return true; } 这里面手动设置为true了,需要自己判断子控件是否滑动到顶部,否则父控件不做拦截,两个问题都已解决

1181631922 avatar Aug 27 '20 03:08 1181631922

第二个问题有两种解决方法: 一:子控件通知父控件不要干涉我的手势事件:

@Override
    public boolean onInterceptTouchEvent(MotionEvent e) {
        /*
        通知父view是否可以截获事件
         */
        final boolean isScrollUp = !canScrollVertically(-1);
        if (isScrollUp) {
            /*
            同父的此重写方法return super.onInterceptTouchEvent(v)
             */
            getParent().requestDisallowInterceptTouchEvent(false);
            Log.d("子dispatchTouchEvent", "子滑动到顶部");
        } else {
            Log.d("子dispatchTouchEvent", "子没有滑动到顶部,可以继续向上滑动");
            /*
            同父的此重写方法的return false
             */
            getParent().requestDisallowInterceptTouchEvent(true);
        }
        return super.onInterceptTouchEvent(e);
    }

二:父控件中直接去不拦截

@Override
    public boolean onInterceptTouchEvent(MotionEvent e) {
        final boolean intercept = super.onInterceptTouchEvent(e);

        if (e != null) {
            final int action = e.getAction();
            switch (action) {
                case MotionEvent.ACTION_DOWN: {
                    Log.d("父dispatchTouchEvent", "ACTION_DOWN");
                }
                case MotionEvent.ACTION_MOVE: {
                    Log.d("父dispatchTouchEvent", "ACTION_MOVE");
                }
                case MotionEvent.ACTION_CANCEL: {
                    Log.d("父dispatchTouchEvent", "ACTION_CANCEL");
                }
                case MotionEvent.ACTION_UP: {
                    Log.d("父dispatchTouchEvent", "ACTION_UP");
                }
            }
        }
        RecyclerView childRecyclerView = findNestedScrollingChildRecyclerView();
        if (childRecyclerView != null) {
            boolean isScrollUp = !childRecyclerView.canScrollVertically(-1);
            if (isScrollUp) {
                Log.d("父dispatchTouchEvent", "子滑动到顶部");
            } else {
                Log.d("父dispatchTouchEvent", "子没有滑动到顶部,可以继续向上滑动");
                return false;
            }
        }
        if (intercept) {
            Log.d("父dispatchTouchEvent", "父控件拦截手势了");
        } else {
            Log.d("父dispatchTouchEvent", "父控件未拦截手势");
        }
        return intercept;
    }

1181631922 avatar Aug 27 '20 07:08 1181631922

上面两种方法有bug,第二种方法暂时废弃,第一种方法需要加上判断,如下,否则viewpager划不动 如下:

    private var oldX = 0F
    private var oldY = 0F

    private var newX = 0F
    private var newY = 0F

    override fun onInterceptTouchEvent(e: MotionEvent): Boolean {
        val intercept = super.onInterceptTouchEvent(e)
        if (e != null) {
            val action = e.action
            when (action) {
                MotionEvent.ACTION_DOWN -> run {
                    oldX = e.x
                    oldY = e.y
                    Log.d("dispatchTouchEvent", "parent ACTION_DOWN")
                }
                MotionEvent.ACTION_MOVE -> run {
                    newX = e.x
                    newY = e.y
                    Log.d(
                        "onInterceptTouchEvent",
                        "onInterceptTouchEvent parent oldX:" + oldX + ",oldY:" + oldY
                    )
                    Log.d(
                        "onInterceptTouchEvent",
                        "onInterceptTouchEvent parent newX:" + newX + ",newY:" + newY
                    )
                    oldX = newX
                    oldY = newY
                }
                MotionEvent.ACTION_CANCEL -> run {
                    Log.d("dispatchTouchEvent", "parent ACTION_CANCEL")
                }
                MotionEvent.ACTION_UP -> run {
                    Log.d("dispatchTouchEvent", "parent ACTION_UP")
                }
            }
        }
        val childRecyclerView: RecyclerView? = findNestedScrollingChildRecyclerView()
        if (childRecyclerView != null) {
            val isScrollUp = !childRecyclerView.canScrollVertically(-1)
            if (isScrollUp) {
                Log.d("dispatchTouchEvent", "parent 子滑动到顶部")
            } else {
                Log.d("dispatchTouchEvent", "parent 子没有滑动到顶部,可以继续向上滑动")
                /*
                不再这里去处理手势了,放在子中,不用去查询view,提高效率
                如果x轴偏移量大于y轴此时父控件先去处理,之后再交给子控件
                 */
                return if (abs(newX - oldX) > abs(newY - oldY)) {
                    intercept
                } else {
                    false
                }
            }
        }
        if (intercept) {
            Log.d("dispatchTouchEvent", "parent 父控件拦截手势了")
        } else {
            Log.d("dispatchTouchEvent", "parent 父控件未拦截手势")
        }
        return intercept
    }

1181631922 avatar Sep 21 '20 01:09 1181631922

第二种方法暂时废弃,第一种方法需要加上判断

两种方法(外部拦截和 内部拦截)都可以进行加入判断使 ViewPager 滑动。

trycatchx avatar Oct 22 '20 10:10 trycatchx

这里还有两个问题,就是三层嵌套滑动的fling还是有问题,等待解决后会提交解决方案 另外一个问题是三层嵌套滑动,如果父Recyclerview滑动到底部,子Recyclerview viewpager切换会有问题

1181631922 avatar Jan 18 '21 02:01 1181631922