这里接着上一篇文章 通过NestedScrolling实现RecyclerView拖拽回弹效果,做了一些优化并增加滑动动画效果。
首先看下我们要实现的效果:

饿了么效果

我们的效果
功能很简单,需要给RecyclerView做两个扩展:
一、增加拖拽功能
拖拽功能在上一章已经做了介绍,但有几点需要注意:
1、拖拽范围限制
    @Override
    public void scrollTo(int x, int y) {
        if (x < 0) {
            x = 0;
        } else if (x > maxWidth * 2) {
            x = maxWidth * 2;
        }
        super.scrollTo(x, y);
    }
2、惯性问题:当RecyclerView在界面之内交给它自己惯性滑动
    @Override
    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
        // 当RecyclerView在界面之内交给它自己惯性滑动
        return getScrollX() != maxWidth;
    }
3、快速左右连续滑动会出现错位问题,需要要限制处理
@Override
    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
        ...
        // 限制错位问题
        if (dx > 0 && getScrollX() > maxWidth && !ViewCompat.canScrollHorizontally(target, -1)) {
            scrollTo(maxWidth, 0);
        }
        if (dx < 0 && getScrollX() < maxWidth && !ViewCompat.canScrollHorizontally(target, 1)) {
            scrollTo(maxWidth, 0);
        }
    }
4、动画问题:和惯性同样判断什么时候开启动画
    @Override
    public void onStopNestedScroll(View target) {
        mParentHelper.onStopNestedScroll(target);
        // 如果不在RecyclerView滑动范围内
        if(maxWidth != getScrollX()){
            startAnimation(new ProgressAnimation());
        }
    }
5、多点触控问题:在动画执行时期不处理事件
    @Override
    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
        return target instanceof RecyclerView && !isRunAnim;
    }
    mChildView.setOnTouchListener(new OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    // 保证动画状态中 子view不能滑动
                    return isRunAnim;
                }
    });
二、根据拖拽距离绘制椭圆
1、首先要保证查看更多按钮一直在最右边显示
有两个思路:
(1)自定义扩展得View宽度固定,查看更多按钮位置随着滑动距离变化。
(2)自定义扩展的View宽度随着滑动距离变化,查看更多按钮右居中显示。
2、滑动显示出更多按钮后,开始绘制椭圆。
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPath.reset();
        float marginTop = (mHeight - mLayoutHeight) / 2;
        // 右上角x坐标、右上角y坐标
        mPath.moveTo(mMove - mLayoutWidth, marginTop);
        // 左边弧形x坐标、左边弧形y坐标、右下角x坐标、右下角y坐标
        mPath.quadTo(0,  mHeight / 2, mMove - mLayoutWidth, mLayoutHeight + marginTop);
        canvas.drawPath(mPath, mBackPaint);
    }
demo地址:https://github.com/eatdefecat/DZStickyNavLayout
最后还有个问题很困扰我,如果没有给RecyclerView中itemView设置可以点击,onStartNestedScroll会执行2次,并且onNestedPreScroll方法里返回的dx或者dy会变得很大,实现不了阻力效果。如果有知道这是什么原因引起的欢迎在文章下面留言。