RecyclerView三种显示方式的下拉刷新和上拉加载更多


有关RecyclerView的类似SwipeRefreshLayout的上拉加载更多,我写了一篇博客http://blog.csdn.net/cj_286/article/details/52767070

但是之前写的那个有一点点的小问题,如果上拉刷新,刷新小图标还没有移动到刷新位置,刷新数据就已经获取到,并且调用了setRefreshing(false),在setRefreshing(false)中会去调用translationTo(int from,int to,final boolean isShow),将刷新图标隐藏,而在上拉刷新的时候,也会去调用translationTo(int from,int to,final boolean isShow),将图标移动到刷新位置,就在移动过程中还没有结束,就调用了停止刷新,这样就会出现问题,所以解决办法就是如果在上拉加载更多的时候,如果刷新图标还没有移动到刷新位置就调用了setRefreshing(false)来停止刷新,这是就要等待让其移动到指定位置之后再停止,所以就需要提供一个借口监听,上拉刷新图标到指定位置回调该接口,在setRefreshing(false)中如果上拉刷新图标还在移动过程中就设置监听,在监听回调中再去停止刷新,这样就解决了以上的bug.

translationTo(int from,int to,final boolean isShow)方法修改后的代码如下:

/**
     * 执行平移动画
     * @param from
     * @param to
     */
    private void translationTo(int from,int to,final boolean isShow){
        //1.调用ofInt(int...values)方法创建ValueAnimator对象
        ValueAnimator mAnimator = ValueAnimator.ofInt(from,to);
        //2.为目标对象的属性变化设置监听器
        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                // 3.为目标对象的属性设置计算好的属性值
                int animatorValue = (int)animation.getAnimatedValue();
                MarginLayoutParams marginLayoutParams = (MarginLayoutParams) mImageView.getLayoutParams();
                marginLayoutParams.bottomMargin = animatorValue;
                mImageView.setLayoutParams(marginLayoutParams);
            }
        });
        mAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                if(isShow){
                    start();
                    mPrepareAnimation = false;
                    //设置准备刷新的回调,防止在没有到刷新的位置,就已经调用了setRefreshing(false)来停止刷新,这样就会出现问题
                    //内部使用
                    if(mPrepareAnimationListener != null){
                        mPrepareAnimationListener.finishAnimation();
                    }
                }else{
                    hideRefreshArrow();
                    hide();
                }

            }
        });
        //4.设置动画的持续时间、是否重复及重复次数等属性
        mAnimator.setDuration(100);
        //mAnimator.setRepeatCount(3);
        mAnimator.setRepeatMode(ValueAnimator.INFINITE);
        //5.为ValueAnimator设置目标对象并开始执行动画
        mAnimator.setTarget(mImageView);
        mAnimator.start();
    }
监听接口定义

/**
     * 准备刷新动画的监听,就是上拉后,移动到刷新位置的监听
     */
    interface PrepareAnimationListener{
        void finishAnimation();
    }

    private PrepareAnimationListener mPrepareAnimationListener;

    private void setPrepareAnimationListener(PrepareAnimationListener listener){
        mPrepareAnimationListener = listener;
    }
setRefreshing(boolean refreshing)代码修改后如下:

/**
     * 加载更多或停止加载更多
     * @param refreshing
     */
    public void setRefreshing(boolean refreshing) {
        if(!mIsAllowLoadMore) return;
        if(refreshing){
            if(mStart) return;
            showRefreshArrow();
            getValueToTranslation();
            mPrepareAnimation = true;

            mIsRefreshing = true;//正在刷新

            if (mOnPullListener != null) {
                mOnPullListener.onLoadMore(this);
            }
            mIsCanScoll = false;
        }else {
            //如果准备执行动画(平移到刷新转圈的位置)结束后才能停止
            if(!mPrepareAnimation) {
                setRefreshStop();
            }else{
                //上拉加载的View还没有到刷新转圈的地方,就停止了刷新,所以要设置准备刷新的监听,
                //等到刷新的地方了,再调用停止刷新
                setPrepareAnimationListener(new PrepareAnimationListener() {
                    @Override
                    public void finishAnimation() {
                        setRefreshStop();
                    }
                });
            }
        }
    }

在解决以上的问题后,之前的PullRefreshLayout并不支持StaggeredGridLayoutManager(瀑布流)的上拉加载更多,这次将其加上,要想实现瀑布流的上拉刷新,在瀑布流显示方式的时候,向上滑动时,要不断的去获取,瀑布流中显示在最下面的条目布局的getBottom(),如果在下面的条目布局的getBottom()<= getHeight()时,就说明已经到底了,应该去上拉刷新了,那么如何去获取最下面的条目布局呢,StaggeredGridLayoutManager提供了一个findLastVisibleItemPositions(int[])方法,该方法是获取瀑布流的每一列的最后一个的条目的索引,然后再根据findViewByPosition(int)去获取条目布局,条目布局获取到了就可以得到getBottom(),获取没一列最后一个条目的getBottom(),取其最大的一个与getHeight()相比,如果小于等于就说明到底了,该刷新了。
获取最后一个可见条目的索引

/**
     * 获取底部可见项的位置
     * 获取最后一个条目的索引
     * @param lastPos 如果是瀑布流的话就返回每一列最后一个条目的索引
     * @return
     */
    private int getLastVisibleItemPosition(int[] lastPos) {
        RecyclerView.LayoutManager lm = mRecyclerView.getLayoutManager();
        int lastVisibleItemPosition = 0;
        if (lm instanceof GridLayoutManager) {
            lastVisibleItemPosition = ((GridLayoutManager) lm).findLastVisibleItemPosition();
        } else if (lm instanceof LinearLayoutManager) {
            lastVisibleItemPosition = ((LinearLayoutManager) lm).findLastVisibleItemPosition();
        }else if(lm instanceof StaggeredGridLayoutManager){
            StaggeredGridLayoutManager layoutManager = (StaggeredGridLayoutManager)lm;
            int columnCount = layoutManager.getColumnCountForAccessibility(null, null);//获取瀑布流的列数
            //int columnCount = layoutManager.getSpanCount();//获取瀑布流的列数
            int[] positions = new int[columnCount];
            layoutManager.findLastVisibleItemPositions(positions);//获取瀑布流的每一列的最下面的条目的索引(并不是最后n个(n为瀑布流的列数)),有的条目可能会很长
            lastVisibleItemPosition = getArrayMax(positions);//返回其中最大的一个(它是乱序的,并不是按顺序保存的)
            System.arraycopy(positions,0,lastPos,0,positions.length);
            //瀑布流的布局方式是哪一列的高度最小,下一个条目就排到哪一列的后面
        }
        return lastVisibleItemPosition;
    }
瀑布流是否已经到底部了

/**
     * 判断最后几个有一个到底部了就说明到底部了
     * @param layoutManagers
     * @param lastPos
     * @return
     */
    private boolean staggeredCanPullUp(RecyclerView.LayoutManager layoutManagers, int[] lastPos){
        if(!(layoutManagers instanceof StaggeredGridLayoutManager)) return false;
        int bottom = 0;
        for(int i=0;i<lastPos.length ; i++){
            /**
             * 判断lastItem的底边到recyclerView顶部的距离
             * 是否小于recyclerView的高度
             * 如果小于或等于 说明滚动到了底部
             * 这样有一个弊端,可能有某一列显示不全就加载更多了
             */
//            if(layoutManagers.findViewByPosition(lastPos[i]).getBottom() <= getHeight() ){
//                /**
//                 * 已到最后条目的底部了
//                 */
//                return true;
//            }
            /**
             * 这个就不存在以上的弊端了
             */
            //取出每一列的最后一个条目的mBottom,并并取出最大的一个与getHeight()比较
            if(layoutManagers.findViewByPosition(lastPos[i]).getBottom() > bottom) {
                bottom = layoutManagers.findViewByPosition(lastPos[i]).getBottom();
            }

        }
        //return false;
        return bottom <= getHeight();
    }
好了,暂时我就发现这两点问题,如果还有其他的问题或是不合理的地方,欢迎留言

在该Demo中的RecyclerView的万能设配器是CSDN鸿洋博客中的http://blog.csdn.net/lmj623565791/article/details/51118836

下载地址:CSDN




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值