美文网首页
TurboRecyclerViewHelper之实现Recycl

TurboRecyclerViewHelper之实现Recycl

作者: 做麦西西不容易 | 来源:发表于2016-06-01 13:12 被阅读0次

    自从使用了RecyclerView再也回不去了,什么ListView、GridView统统让他们退休了。必须安利起来,用了才能体会它的神奇!

    根据使用RecyclerView以来,拓展的一些功能及对RecyclerView.Adapter的封装,想在这里跟大家分享一些经验,还望指正。

    1. 功能介绍
      ====
      基于对RecyclerView在使用过程中的一些痛点写了这个开源项目 TurboRecyclerViewHelper 。功能点详见README。
    turbo_simple.gif

    本次主要介绍针对TurboRecyclerView上拉/左滑的功能的实现及思路。

    下面直接进入正题...

    1. 状态分析
      ====
      以上拉加载的过程作为本次分享的一个栗子。状态如下图:
    turbo_state_analysis.png

    我们所关心的是RecyclerView滑动到底部的状态,这个状态下是我们需要处理的临界状态
    初始状态以及滑动中的状态我们不需要关心(交给RecyclerView本身处理即可)。

    1. 目标状态的条件限制
      ====
      废话不多说直接看代码:
      if (!mLoadEnabled || canScrollEnd() || mIsLoading || isEmpty()) {
            return super...;
      }
    

    我们从两个方面来分析可以开始处理Touch事件的条件:

    3.1 客观条件

    所谓客观条件即是RecyclerView滑动到底部的这个状态的物理状态,体现在代码上就是

     private boolean canScrollEnd() {
           //判断在纵向是否还能向上滑动
           return ViewCompat.canScrollVertically(this, 1);
     }
    

    这里为了简化只判断了纵向是否可以向下滑动,实际代码中这里是判断条件为ViewCompat.canScrollVertically(this, 1) || ViewCompat.canScrollHorizontally(this, 1)

    这个条件返回值如果是false,则代表我们可以从这个临界状态开始处理Touch事件,否则不处理。

    3.2 逻辑条件(主观条件)

    逻辑条件(或者称为主观条件)是设计控件本身所考虑的限制条件。

    判断条件如下:

        //是否允许上拉 || 是否正处于刷新状态 || 是否处理空状态
        if (!mLoadEnabled || mIsLoading || isEmpty())
    

    在以上条件下我们认为是控件本身应处于不可上拉的状态,我们不做处理。

    1. Touch事件的处理
      ====
      在同时满足客观条件和逻辑条件下,我们就可以开始处理上拉的效果。

    4.1 记录初始值

    我们需要在MotionEvent.ACTION_DOWN MotionEvent.ACTION_POINTER_DOWN时记录初始值:

       mInitialMotionX = getMotionEventX(e, actionIndex);
       mInitialMotionY = getMotionEventY(e, actionIndex);
    

    4.2 判断滑动是否符合预期值

    MotionEvent.ACTION_MOVE时判断是否是上拉的状态:

        //LayoutManager中提供的判断是否纵向可以滑动的方法
        final boolean canScrollVertically = getLayoutManager().canScrollVertically();
        ...
        final int y = getMotionEventY(e, index);
        int deltaY = y - mInitialMotionY;
        if (canScrollVertically && Math.abs(deltaY) > mTouchSlop && deltaY < 0) { ... //处理上拉效果}
    

    记录当前Y值,且判断是否手指在上滑状态。

    4.3 实现上拉效果

    在自定义控件中,实现上拉效果有多种途径,例如大家常用的利用Scroller配合scrollTo来实现滑动,但是在RecyclerView的实现中并不支持这种方式。这个方案Close!

        @Override
        public void scrollTo(int x, int y) {
            Log.w(TAG, "RecyclerView does not support scrolling to an absolute position. "
                    + "Use scrollToPosition instead");
        }
    

    这里采用setTranslationY来实现上拉效果,根据手指移动的距离计算出移动距离来改变RecyclerView的位置。

        ...
        float targetEnd = -dampAxis(deltaY); //阻尼值的计算
        setTranslationY(targetEnd);
        return true;  //消费掉此事件
    

    到这里上拉的效果已经实现完毕。

    4.4 复位及刷新

    距离成功只差一点点。
    在用户手指松开以后,我们要考虑做两件事:RecyclerView的复位及是否可以处于刷新状态。
    针对复位操作,我们只需要逆向setTranslationY值即可。这里我们采用属性动画来实现

        private void animateOffsetToEnd(final String propertyName, final Interpolator interpolator, float... value) {
            if (mResetAnimator == null) {
                mResetAnimator = new ObjectAnimator();
                mResetAnimator.setTarget(this);
            }
            mResetAnimator.cancel();
            mResetAnimator.setPropertyName(propertyName);
            mResetAnimator.setFloatValues(value);
            mResetAnimator.setInterpolator(interpolator);
            mResetAnimator.start();
     }
        
        ...
         
        if(canScrollVertically)
            animateOffsetToEnd("translationY", mInterpolator, 0f);
        ...
    
    

    对于刷新我们要做的事情也比较简单,判断当前移动距离达到阈值后,回调监听事件并显示LOAING_VIEW。

        Log.i(TAG, "refreshing...");
        mIsLoading = true;
        dispatchOnLoadingMoreListeners();
        smoothScrollToPosition(mLastVisibleItemPosition + 1);
    

    刷新完毕后,记得通知TurboRecyclerView更新状态哦!

        mTurboRecyclerView.addOnLoadingMoreListener(new OnLoadMoreListener() {
            @Override
            public void onLoadingMore() {
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mRecyclerView.loadMoreComplete(Arrays.asList(sCheeseStrings));
                    }
                }, 2000);
            }
        });
    

    至此整个上拉到复位刷新的过程完成。
    完整代码详见 TurboRecyclerView.java

    希望我的分享能让您能有所收获。也欢迎支持一下这个项目~ 持续维护~

    下次准备介绍一下对RecyclerView.Adapter的封装,还请关注!😊

    相关文章

      网友评论

          本文标题:TurboRecyclerViewHelper之实现Recycl

          本文链接:https://www.haomeiwen.com/subject/hxehdttx.html