android RecyclerView1.3.2与NestedScrollingParent的变化

这篇文章,可能不懂的人将会不知所云,懂的自然懂,不懂的可能需要遇到类似问题回头来看我的帖子好了。

RecyclerView1.3.0+版本,与1.2.1版本有一个比较大的变化是:内部对于edge的处理不同。
edge是什么?
就是当我们下拉或者上拉(横向RecyclerView则是左右拉),会有一个极限。当到了极限,则会出现边缘效果,就是有一个额外的小头部效果贴在边上。并且,RecyclerView就会出现简单的拉伸变长,以表现它无法继续滑动的现象。

而我们经常会开发下拉刷新功能。那么,就相当于用一个ParentConstraintLayout(以下用parent代替)内部持有一个子View RecyclerView(以下用rcv代替)。

我通过自行解压RecyclerView库1.3.2和1.2.1的代码来对比,最大的差异为:

public boolean onTouchEvent(MotionEvent e) {
		...
       if (mScrollState == SCROLL_STATE_DRAGGING) {
           mReusableIntPair[0] = 0;
           mReusableIntPair[1] = 0;
           dx -= releaseHorizontalGlow(dx, e.getY()); //1.3.2多出来的
           dy -= releaseVerticalGlow(dy, e.getX()); //1.3.2多出来的
           //触发NestedScroll框架的必须
           if (dispatchNestedPreScroll(
                   canScrollHorizontally ? dx : 0,
                   canScrollVertically ? dy : 0,
                   mReusableIntPair, mScrollOffset, TYPE_TOUCH
           )) {
               dx -= mReusableIntPair[0];
               dy -= mReusableIntPair[1];
               // Updated the nested offsets
               mNestedOffsets[0] += mScrollOffset[0];
               mNestedOffsets[1] += mScrollOffset[1];
               // Scroll has initiated, prevent parents from intercepting
               getParent().requestDisallowInterceptTouchEvent(true);
           }
     ....
}

我们知道NestedScrolling框架要求子View告知父View onNestedPreScroll。
因此,这里多的代码,如果把dx, dy变成了0,则会进一步导致直接将原本应该分发给parent的unConsumed值给消费掉了。

那么,对于下拉框架,为了兼容这2种问题。经过长久的思考,禁用掉RecyclerView的edge效果就可以了。releaseVerticalGlow里面就不会做任何事情。而且也符合我们下拉刷新的要求。因为我们不需要edge的边缘拉伸效果,而是将分发事件的多出距离用来做下拉刷新的整体布局往下拉的效果。

因此,给你的rcv实例设置为一个做空事情的Effect即可。
本文确实可能会让你云里雾里,遇到的再来回顾我的话吧。

rcv.edgeEffectFactory = object : RecyclerView.EdgeEffectFactory() {
    override fun createEdgeEffect(view: RecyclerView, direction: Int): EdgeEffect {
        return NoEdgeEffect(view.context)
    }
}

class NoEdgeEffect : EdgeEffect {
    constructor(context: Context?) : super(context)

    @RequiresApi(api = Build.VERSION_CODES.S)
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)

    override fun setSize(width: Int, height: Int) {
        //do nothing.
    }

    override fun isFinished(): Boolean {
        return true
    }

    override fun onPull(deltaDistance: Float) {
        //do nothing.
    }

    override fun onPull(deltaDistance: Float, displacement: Float) {
        //do nothing.
    }

    override fun onPullDistance(deltaDistance: Float, displacement: Float): Float {
        //do nothing.
        return 0f
    }

    override fun onRelease() {
        //do nothing.
    }

    override fun onAbsorb(velocity: Int) {
        //do nothing.
    }

    override fun draw(canvas: Canvas?): Boolean {
    //do nothing.
    return false
}