Android RecyclerView(八)设置自定义 下拉刷新 与 上拉加载数据

Android RecyclerView(八)设置下拉刷新 与 上拉加载数据



GitHub 项目源码

CSDN 博客说明

智慧安卓App 文章分析


下拉刷新效果

下拉刷新效果  图示

上拉加载数据效果

上拉加载数据效果  图示


1 xml布局文件中
<FrameLayout android:layout_width = "match_parent" android:layout_height = "match_parent" >

    <!--背景-->
    <LinearLayout style = "@style/style_bg_ll" >
      <TextView style = "@style/style_bg_tv"
                android:text = "智慧安卓" />
      <TextView style = "@style/style_bg_tv_c1"
                android:text = "网址 www.studyyoun.com" />
      <TextView
        style = "@style/style_bg_tv_c1"
        android:text = "\@2017ICP17005075-1" />
    </LinearLayout >


    <!--数据列表-->
    <android.support.v7.widget.RecyclerView
      android:id = "@+id/rv_list"
      android:layout_width = "match_parent"
      android:layout_height = "match_parent"
      android:background = "#fcfcfc"
      android:visibility = "visible" />


    <!--表层刷新显示布局-->
    <LinearLayout android:id = "@+id/ll_pull_refresh_main"
                  style = "@style/style_refresh_ll"
                  android:visibility = "visible" >
      <ProgressBar android:layout_width = "30dp"
                   android:layout_height = "30dp" />

      <TextView android:id = "@+id/tv_pull_refesh"
                style="@style/style_refresh_tv"
                android:text = "下拉刷新" />

    </LinearLayout >
  </FrameLayout >

其实在这里就是使用了三层布局

1.1 背景

下拉刷新效果  图示

1.2 显示列表数据控件 RecyclerView
1.3 显示刷新布局

下拉刷新效果  图示


2 设置 RecyclerView 显示数据
2.1 初始化数据设置

//刷新布局的高度 dp
private int mPullRefreshDefault=62;
//刷新布局的高度 px 会根据屏幕密度来进行计算
private int mPullRefshLayoutHeight;

private RecyclerView mRecyclerView;
//下拉刷新显示的布局
private LinearLayout mPullRefshLayout;
//下拉刷新中显示的文字提示
private TextView mPullRefTextView;


//对应的布局管理者
private LinearLayoutManager mLinearLayoutManager;

//存储数据的集合
private List<String> mStringList = new ArrayList<>();


//刷新的布局
mPullRefshLayout = (LinearLayout) findViewById(R.id.ll_pull_refresh_main);
//刷新的提示文字
mPullRefTextView = (TextView) findViewById(R.id.tv_pull_refesh);
//列表数据
mRecyclerView = (RecyclerView) findViewById(R.id.rv_list);

//获取当前的屏幕密度数据
DisplayMetrics displayMetrics = new DisplayMetrics();

getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
//获取当前的像素缩放比例
float scaledDensity = displayMetrics.scaledDensity;
//刷新布局文件的高度 mPullRefreshDefault 指定的是 62dp,在这里转换计算成实际的px
mPullRefshLayoutHeight = (int) (mPullRefreshDefault * scaledDensity);
//当视图绘制完成时将显示刷新的布局文件移出
mPullRefshLayout.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout () {
        //将刷新的布局文件移出到屏幕外
        //mPullRefshLayoutHeight 也可以使用mPullRefshLayout.getHeight()替换
        mPullRefshLayout.layout(0, -mPullRefshLayoutHeight, mPullRefshLayout.getWidth(), 0);
    }
});
//初始化模拟数据
for (int i = 0; i < 16; i++) {
    mStringList.add("test " + i);
}

//设置布局样式
mLinearLayoutManager = new LinearLayoutManager(this);
//设置方向
mLinearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
//关联RecyclerView
mRecyclerView.setLayoutManager(mLinearLayoutManager);
//设置分割线
mRecyclerView.addItemDecoration(new DividerItemDecoration(
        this, DividerItemDecoration.VERTICAL));

//关联Adapter
mRecyclerView.setAdapter(mViewHolderAdapter);
//设置滑动监听事件
mRecyclerView.setOnScrollListener(mOnScrollListener);
//设置触摸监听事件
mRecyclerView.setOnTouchListener(mOnTouchListener);

2.2 Adapter 与 ViewHolder的设置
2.2.1 显示正常数据的条目布局 item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android = "http://schemas.android.com/apk/res/android"
                android:layout_width = "match_parent"
                android:layout_height = "match_parent" >

    <LinearLayout android:layout_width = "match_parent"
                  android:layout_height = "wrap_content"
                  android:background = "#fff"
                  android:orientation = "vertical" >
        <TextView android:id = "@+id/tv_item_text"
                  android:layout_width = "match_parent"
                  android:layout_height = "80dp"
                  android:text="测试数据"
                  android:background = "#acd972"
                  android:gravity = "center" />
    </LinearLayout >

</RelativeLayout >

上拉加载数据效果  图示

2.2.2 显示刷新数据的条目布局 refresh_view_footer.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android = "http://schemas.android.com/apk/res/android"
                android:layout_width = "match_parent"
                android:layout_height = "match_parent"
                android:background = "#232323"
                android:orientation = "vertical" >

    <LinearLayout android:layout_width = "match_parent"
                  android:layout_height = "match_parent"
                  android:gravity = "center"
                  android:orientation = "horizontal" >
        <ProgressBar android:layout_width = "30dp"
                     android:layout_height = "30dp" />
        <TextView android:id = "@+id/tv_loading_more"
                  android:layout_width = "wrap_content"
                  android:layout_height = "45dp"
                  android:layout_marginLeft = "18dp"
                  android:gravity = "center"
                  android:text = "正在加载更多数据"
                  android:textColor = "#fff"
                  android:textSize = "14sp" />
    </LinearLayout >

</RelativeLayout >

上拉加载数据效果  图示

2.2.3 数据设置


需要注意的是,在这里,设置的是当显示的数据条目大于10条时,才启动上拉加载更多数据

这是处理当数据为少量时,下拉刷新与上拉加载更多冲突的一种方式


private RecyclerView.Adapter<ViewHolder> mViewHolderAdapter = new RecyclerView.Adapter<ViewHolder>() {
    @Override
    public ViewHolder onCreateViewHolder (ViewGroup parent, int viewType) {

        if (viewType == 0) {
            //加载条目布局文件
            View view = View.inflate(HomeActivity.this, R.layout.item, null);
            //创建ViewHolder
            CustomViewHolder customViewHolder = new CustomViewHolder(view);
            return customViewHolder;
        } else {
            //最后一个条目设置刷新布局显示
            View view = View.inflate(HomeActivity.this, R.layout.refresh_view_footer, null);
            //创建ViewHolder
            UpLoadViewHolder customViewHolder = new UpLoadViewHolder(view);
            return customViewHolder;
        }
    }

    @Override
    public void onBindViewHolder (ViewHolder holder, int position) {

        //根据position来获取ViewHolder的类型
        int itemViewType = this.getItemViewType(position);

        if (itemViewType == 0) {
            //获取 显示普通数据 Holder
            CustomViewHolder viewHolder = (CustomViewHolder) holder;

            String s = mStringList.get(position);
            //设置数据
            viewHolder.setDatas(position, s);

        } else {
            //最后一个条目 获取刷新布局对应的Holder
            UpLoadViewHolder viewHolder = (UpLoadViewHolder) holder;
            viewHolder.setDatas(position);

        }
    }

    @Override
    public int getItemCount () {
        /**
         * 只有当显示的条目个数大于10 才启用上拉到底部加载更多数据功能
         * 也就是只有当显示的条目个数大于10 时,才多返回一个条目 
         * 用来设置显示加载更多的布局
         */

        if (mStringList == null) {
            return 0;
        } else if (mStringList.size() > 10) {
            return mStringList.size() + 1;
        } else {
            return mStringList.size();
        }
    }

    @Override
    public int getItemViewType (int position) {
        if (mStringList.size() > 10) {
         /**
          * 只有当显示的条目个数大于10 时,在显示最后一条数据时
          * 此时是无数据内容,用来显示上拉刷新布局,这里返回1为标识
          */
            if (position == mStringList.size()) {
                //如果是最后一个条目 那么返回1
                //用来加载显示刷新布局
                return 1;
            } else {
                //用来加载显示普通布局
                return 0;
            }
        } else {
            //用来加载显示普通布局
            return 0;
        }

    }
};
//普通加载项的ViewHolder
private static class CustomViewHolder extends ViewHolder {

    private final TextView mTextView;

    public CustomViewHolder (View itemView) {
        super(itemView);
        mTextView = (TextView) itemView.findViewById(R.id.tv_item_text);
    }

    public void setDatas (int position, String s) {
        mTextView.setText(s);

    }
}
//上拉加载更多的 ViewHolder
private static class UpLoadViewHolder extends ViewHolder {

    private final TextView mTextView;

    public UpLoadViewHolder (View itemView) {
        super(itemView);
        mTextView = (TextView) itemView.findViewById(R.id.tv_loading_more);
    }


    public void setDatas (int position) {

    }
}
3 RecyclerView 的 OnScrollListener (滑动监听事件) 中实现上拉加载数据功能
//设置滑动监听事件
mRecyclerView.setOnScrollListener(mOnScrollListener);
//当前屏幕上显示的最后一个条目数据对应的位置
private int mLastVisibleItemPosition;
//当前屏幕显示的第一个条目数据对应的位置
private int mFirstVisibleItemPosition;
//获取当前RecyclerView完全显示出的第一个条目的位置
private int mFirstCompletelyVisibleItemPosition;
//获取当前RecyclerView完全显示出的最后一个条目的位置
private int mLastCompletelyVisibleItemPosition;

/**
 * RecyclerView是否滑动到了顶部 只有滑动到了顶部才可以启用下拉刷新功能
 * 这里通过RecyclerView的布局管理者 mLinearLayoutManager来动态的获取当前屏幕上显示的RecyclerView的第一个条目对应的 角标索引
 */
private boolean mIsToTop = true;

/**
 * 上拉加载更多数据 是否正在加载
 * 当正在加载更多数据时,此时可能还会滑动RecyclerView 
 * 为防止同时发起多次请求数据 所设置的标识
 */
private boolean mIsLoading = false;
/**
 * RecyclerView 的滑动监听事件
 * 在这里可以判断RecyclerView是否滑动到了顶部
 * 在这里用来判断RecyclerView是否滑动到了底部
 */
private OnScrollListener mOnScrollListener = new OnScrollListener() {

    @Override
    public void onScrolled (RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        //根据当前的布局管理都来获取显示的条目位置
        if (mLinearLayoutManager != null) {
            //获取当前RecyclerView显示最后一个条目的位置
            mLastVisibleItemPosition = mLinearLayoutManager.findLastVisibleItemPosition();
            //获取当前RecyclerView显示的第一个条目的位置
            mFirstVisibleItemPosition = mLinearLayoutManager.findFirstVisibleItemPosition();

            //获取当前RecyclerView完全显示出的最后一个条目的位置
            mLastCompletelyVisibleItemPosition = mLinearLayoutManager.findLastCompletelyVisibleItemPosition();

            //获取当前RecyclerView完全显示出的第一个条目的位置
            mFirstCompletelyVisibleItemPosition = mLinearLayoutManager.findFirstCompletelyVisibleItemPosition();

            /**
             * 当RecyclerView 显示的第一个条目 完全加载出来时
             *      mFirstVisibleItemPosition 为 0
             *      mFirstCompletelyVisibleItemPosition 也为0
             * 当RecyclerView 显示的第一个条目 并没有完全加载出来,也就是显示了一半(显示不完全 )
             *      mFirstVisibleItemPosition 为 0
             *      mFirstCompletelyVisibleItemPosition 为1
             *
             * 所以 当mFirstCompletelyVisibleItemPosition 为 0 表示 完全滑动到了顶部
             */

            if (mFirstCompletelyVisibleItemPosition == 0) {
                //更新滑动到顶部标识
                mIsToTop = true;
                Log.e("scroll ", "滑动到顶部 ");
            } else {
                //更新滑动到顶部标识 false不在顶部
                mIsToTop = false;
                //获取当前屏幕上显示的条目的个数
                int childCount = mLinearLayoutManager.getChildCount();
                //获取总共的条目个数
                int itemCount = mLinearLayoutManager.getItemCount();

                //当显示的条目数据大于10条时 才启用上拉加载更多功能
                if (itemCount > 10) {
                    //当显示出最后一个条目时
                    if (mLastVisibleItemPosition==itemCount-1) {
                        log("大于10 可以加载更多 " + itemCount);
                        //加载更多
                        if (!mIsLoading) {
                            //更新加载标识
                            mIsLoading = true;
                            //加载更多数据
                            loadMoreData();
                        }
                    }
                } else {
                    log("小于10 不可以加载更多 " + itemCount + " " + childCount);
                }
            }
        }


    }

    @Override
    public void onScrollStateChanged (RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        if (mViewHolderAdapter != null) {
            //当滑动停止时
            if (newState == RecyclerView.SCROLL_STATE_IDLE) {

            }
        }
    }

};


走到这里呢就基本上可以实现 上拉加载更多数据的功能了

上拉加载数据效果  图示

4 RecyclerView 的 OnTouchListener (触摸监听事件) 中实现下拉刷新数据功能
//设置触摸监听事件
mRecyclerView.setOnTouchListener(mOnTouchListener);
private OnTouchListener mOnTouchListener = new OnTouchListener() {
    @Override
    public boolean onTouch (final View v, MotionEvent event) {
        switch (event.getAction()) {
            //手指按下
            case MotionEvent.ACTION_DOWN:
                    .... .... ....(4.1 中代码说明)
                break;
            //手指移动
            case MotionEvent.ACTION_MOVE:

                        .... .... .... 
                break;
            //手指抬起
            case MotionEvent.ACTION_UP:
                        .... .... .... 
                break;

    }
};
/**
 * 下拉刷新状态标识
 */
public enum RefresState {
    PULL_DEFAULE,//开始默认
    PULL_SHOW,//显示释放加载
    PULL_LOADING,//显示正在加载中
    PULL_LOADING_FINISH//显示刷新完毕
}

上拉加载数据效果  图示

4.1 手指按下时

//手指按下的位置
private float mDownY;
//手指按下时 刷新控件的位置 
private int mPullTop;
//手指按下时 RecyclerView控件的位置
private int mRecyTop;
//手指按下标识
public boolean mIsDown = false;

case MotionEvent.ACTION_DOWN:


        /**
         * mValueAnimator 是当手指离开屏幕时,页面显示布局文件滚回原始默认位置或者指定位置的 动画
         * 
         * 当手指按下去时,如果当前的下拉刷新布局或者 RecyclerView 正在移动,需要停止
         */
        if (mValueAnimator != null) {
            if (mValueAnimator.isRunning() || mValueAnimator.isStarted()) {
                mValueAnimator.cancel();
            }
        }

        //获取手指按下的纵坐标
        mDownY = event.getRawY();
        //获取刷新控件当前的位置
        mPullTop = mPullRefshLayout.getTop();
        //获取列表控件当前的位置
        mRecyTop = mRecyclerView.getTop();
        //手指按下的标识
        mIsDown = true;

        log("top is mRecyTop" + mRecyTop + "    mPullTop  " + mPullTop);

        break;
4.2 手指移动时

上拉加载数据效果  图示

case MotionEvent.ACTION_MOVE:

    //获取实时手指触摸屏幕的 Y轴位置
    float moveY = event.getRawY();
    //计算 手指移动的距离
    int flagY = (int) (moveY - mDownY);
    /**
     * 缩小 要不布局会随着滑动的距离变化太大
     *  flagY >0 向下滑动
     *  flagY < 0向上滑动
     */
    flagY = flagY / 2;


    //当RecyclerView滑动到顶部的时候才可以拖动
    if (mIsToTop) {

        if (mCurrentRefresState == RefresState.PULL_DEFAULE) {

            /**
             * PULL_DEFAULE 状态时 RecyclerView处于屏幕的顶部
             *  向上滑动时不做处理
             *  向下滑动时 处理移动
             */
            if (flagY >= 0) {
                /**
                 * 当下滑到一定距离(显示刷新布局 mPullRefshLayout完全显示出来后)
                 * 更新状态为 PULL_SHOW
                 * 更新刷新布局的显示
                 */
                if (mPullRefshLayout.getTop() >= 0) {
                    if (mCurrentRefresState != RefresState.PULL_SHOW) {
                        mCurrentRefresState = RefresState.PULL_SHOW;
                        mPullRefTextView.setText("释放刷新");
                    }
                }
                //RecyclerView 位置限定
                int recyTop = mRecyTop + flagY;

                if (recyTop <= 0) {
                    recyTop = 0;
                }
                int recyBottom = mRecyclerView.getHeight() + recyTop;

                //下拉刷新位置限定
                int pullTop = mPullTop + flagY;
                if (pullTop <= -mPullRefshLayoutHeight) {
                    pullTop = -mPullRefshLayoutHeight;
                }
                int pullBottom = mPullRefshLayout.getHeight() + pullTop;

                //重新设置RecyclerView的显示
                setRecyclerViewLayout(getRecyclerViewRect(recyTop, recyBottom));
                //重新设置刷新布局文件的显示
                setPullRefreshLayout(getPullRefreshLayoutRect(pullTop, pullBottom));


                return true;
            }
        } else if (mCurrentRefresState == RefresState.PULL_SHOW) {

            int recyTop = mRecyTop + flagY;
            int recyBottom = mRecyclerView.getHeight() + recyTop;


            //更新列表的

            int pullTop = mPullTop + flagY;
            if (pullTop <= -mPullRefshLayoutHeight) {
                pullTop = -mPullRefshLayoutHeight;
            }
            int pullBottom = mPullRefshLayout.getHeight() + pullTop;

            /**
             * mPullRefshLayout没完全显示出来
             * 也就是 mPullRefshLayout.getTop() < 0
             * 更新为 PULL_DEFAULE 状态
             */
            if (mPullRefshLayout.getTop() < 0) {
                if (mCurrentRefresState != RefresState.PULL_DEFAULE) {
                    mCurrentRefresState = RefresState.PULL_DEFAULE;
                    mPullRefTextView.setText("下拉刷新");
                }
            }

            //重新设置RecyclerView的显示
            setRecyclerViewLayout(getRecyclerViewRect(recyTop, recyBottom));
            //重新设置刷新布局文件的显示
            setPullRefreshLayout(getPullRefreshLayoutRect(pullTop, pullBottom));


            return true;
        } else if (mCurrentRefresState == RefresState.PULL_LOADING) {

            /**
             * 正在加载中 状态
             *
             * 在这里设置的是 如果下拉刷新正在进行中
             * 那么只允许下拉 不可上滑
             */
            if (flagY > 0) {

                int recyTop = mRecyTop + flagY;
                int recyBottom = mRecyclerView.getHeight() + recyTop;



                //更新列表的
                int pullTop = mPullTop + flagY;
                int pullBottom = mPullRefshLayout.getHeight() + pullTop;


                //重新设置RecyclerView的显示
                setRecyclerViewLayout(getRecyclerViewRect(recyTop, recyBottom));
                //重新设置刷新布局文件的显示
                setPullRefreshLayout(getPullRefreshLayoutRect(pullTop, pullBottom));


                return true;
            } else {
                return true;
            }
        } else if (mCurrentRefresState == RefresState.PULL_LOADING_FINISH) {


            /**
             * 加载完成 状态
             *
             * 在这里设置的是 如果下拉刷新正在进行中
             * 那么只允许下拉 不可上滑
             */
            int recyTop = mRecyTop + flagY;
            if (recyTop <= 0) {
                recyTop = 0;
            }
            int recyBottom = mRecyclerView.getHeight() + recyTop;



            //更新列表的

            int pullTop = mPullTop + flagY;
            if (pullTop <= -mPullRefshLayoutHeight) {
                pullTop = -mPullRefshLayoutHeight;
            }
            int pullBottom = mPullRefshLayout.getHeight() + pullTop;


            //重新设置RecyclerView的显示
            setRecyclerViewLayout(getRecyclerViewRect(recyTop, recyBottom));
            //重新设置刷新布局文件的显示
            setPullRefreshLayout(getPullRefreshLayoutRect(pullTop, pullBottom));

            return true;

        }


    }
4.3 手指抬起时
case MotionEvent.ACTION_UP:


    //手指抬起
    mIsDown = false;

    //获取RecyclerView当前的位置
    final int recyUpTop = mRecyclerView.getTop();

    /**
     * PULL_DEFAULE  状态,弹回初始默认隐藏页面
     */
    if (mCurrentRefresState == RefresState.PULL_DEFAULE) {
        //不刷新,隐藏
        mValueAnimator = ValueAnimator.ofFloat(1f, 0f);
        mValueAnimator.setDuration(mPullDuration);
        mValueAnimator.addUpdateListener(new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate (ValueAnimator animation) {
                //0 -- 1
                Float value = (Float) animation.getAnimatedValue();


                int recyTop = (int) (recyUpTop * value);

                int recyBottom = mRecyclerView.getHeight() + recyTop;


                int pullTop = recyTop - mPullRefshLayoutHeight;

                int pullBottom = mPullRefshLayout.getHeight() + pullTop;

                //重新设置RecyclerView的显示
                setRecyclerViewLayout(getRecyclerViewRect(recyTop, recyBottom));
                //重新设置刷新布局文件的显示
                setPullRefreshLayout(getPullRefreshLayoutRect(pullTop, pullBottom));


            }
        });
        //开启
        mValueAnimator.start();
    } else if (mCurrentRefresState == RefresState.PULL_SHOW || mCurrentRefresState == RefresState.PULL_LOADING) {
        /**
         * PULL_SHOW        状态
         * PULL_LOADING     状态
         * 都将进入显示 加载中数据状态
         */
        log("up state is  " + mCurrentRefresState);
        //设置文字
        mPullRefTextView.setText("正在加载中");
        //正在加载中状态
        if (mCurrentRefresState != RefresState.PULL_LOADING) {
            mCurrentRefresState = RefresState.PULL_LOADING;
            //加载更多数据方法
            loadingRefresDataFunction();
        }

        //刷新 显示正在加载中
        mValueAnimator = ValueAnimator.ofFloat(0f, 1f);
        mValueAnimator.setDuration(mPullDuration);
        mValueAnimator.addUpdateListener(new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate (ValueAnimator animation) {
                //0 -- 1
                Float value = (Float) animation.getAnimatedValue();

                int recyTop = (int) (recyUpTop - ((recyUpTop - mPullRefshLayoutHeight) * value));
                int recyBottom = mRecyclerView.getHeight() + recyTop;


                int pullTop = recyTop - mPullRefshLayoutHeight;
                int pullBottom = mPullRefshLayout.getHeight() + pullTop;


                //重新设置RecyclerView的显示
                setRecyclerViewLayout(getRecyclerViewRect(recyTop, recyBottom));
                //重新设置刷新布局文件的显示
                setPullRefreshLayout(getPullRefreshLayoutRect(pullTop, pullBottom));


            }
        });
        mValueAnimator.addListener(new AnimatorListener() {
            @Override
            public void onAnimationStart (Animator animation) {

            }

            @Override
            public void onAnimationEnd (Animator animation) {
                mCurrentRefresState = RefresState.PULL_LOADING;
            }

            @Override
            public void onAnimationCancel (Animator animation) {

            }

            @Override
            public void onAnimationRepeat (Animator animation) {

            }
        });
        mValueAnimator.start();
    } else if (mCurrentRefresState == RefresState.PULL_LOADING_FINISH) {
        log("up state is loading_finish ");
        //设置文字
        mPullRefTextView.setText("已更新数据完成");

        //关闭刷新
        mValueAnimator = ValueAnimator.ofFloat(1f, 0f);
        mValueAnimator.setDuration(mPullDuration);
        mValueAnimator.addUpdateListener(new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate (ValueAnimator animation) {
                //0 -- 1
                Float value = (Float) animation.getAnimatedValue();


                int recyTop = (int) (recyUpTop * value);

                int recyBottom = mRecyclerView.getHeight() + recyTop;


                int pullTop = recyTop - mPullRefshLayoutHeight;

                int pullBottom = mPullRefshLayout.getHeight() + pullTop;

                //重新设置RecyclerView的显示
                setRecyclerViewLayout(getRecyclerViewRect(recyTop, recyBottom));
                //重新设置刷新布局文件的显示
                setPullRefreshLayout(getPullRefreshLayoutRect(pullTop, pullBottom));


            }
        });
        mValueAnimator.addListener(new AnimatorListener() {
            @Override
            public void onAnimationStart (Animator animation) {

            }

            @Override
            public void onAnimationEnd (Animator animation) {
                //更新为初始状态
                mCurrentRefresState = RefresState.PULL_DEFAULE;
            }

            @Override
            public void onAnimationCancel (Animator animation) {

            }

            @Override
            public void onAnimationRepeat (Animator animation) {

            }
        });
        mValueAnimator.start();
    }

    break;
4.4 重新设置RecyclerView与pullRefreshLayout布局大小的方法
/**
 * 将RecyclerView 的left top right bottom 封装到Rect
 */
public Rect getRecyclerViewRect (int top, int bottom) {
    return new Rect(mRecyclerView.getLeft(), top, mRecyclerView.getWidth(), bottom);
}

/**
 * 重新布局RecyclerView 并进行刷新
 */
public void setRecyclerViewLayout (Rect rect) {
    mRecyclerView.layout(rect.left, rect.top, rect.right, rect.bottom);
    mRecyclerView.invalidate();
}

public Rect getPullRefreshLayoutRect (int top, int bottom) {
    return new Rect(mPullRefshLayout.getLeft(), top, mPullRefshLayout.getWidth(), bottom);
}

public void setPullRefreshLayout (Rect rect) {
    mPullRefshLayout.layout(rect.left, rect.top, rect.right, rect.bottom);
    mPullRefshLayout.invalidate();
}

4.5 加载完数据后需要关闭加载中状态
public void closePullRefresh () {
    log("加载完成");
    //加载完成
    mCurrentRefresState = RefresState.PULL_LOADING_FINISH;
    //更新显示
    mPullRefTextView.setText("刷新数据完成");

    if (mIsDown) {
        //正在滑动中不需要结束布局显示
    } else {
        log("结束刷新");
        closePullRefresh(true);
    }
}

public void closePullRefresh (boolean flag) {

    if (flag) {

        mValueAnimator = ValueAnimator.ofFloat(1f, 0f);
        mValueAnimator.setDuration(mPullDuration);
        mValueAnimator.addListener(new AnimatorListener() {
            @Override
            public void onAnimationStart (Animator animation) {

            }

            @Override
            public void onAnimationEnd (Animator animation) {
                mCurrentRefresState = RefresState.PULL_DEFAULE;
                //更新列表
                mViewHolderAdapter.notifyDataSetChanged();
            }

            @Override
            public void onAnimationCancel (Animator animation) {

            }

            @Override
            public void onAnimationRepeat (Animator animation) {

            }
        });

        mValueAnimator.addUpdateListener(new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate (ValueAnimator animation) {

                //1 --- 0
                Float value = (Float) animation.getAnimatedValue();


                int recyTop = (int) (mPullRefshLayoutHeight * value);

                int recyBottom = mRecyclerView.getHeight() + recyTop;


                int pullTop = recyTop - mPullRefshLayoutHeight;

                int pullBottom = mPullRefshLayout.getHeight() + pullTop;

                //重新设置RecyclerView的显示
                setRecyclerViewLayout(getRecyclerViewRect(recyTop, recyBottom));
                //重新设置刷新布局文件的显示
                setPullRefreshLayout(getPullRefreshLayoutRect(pullTop, pullBottom));


            }

        });


        mValueAnimator.start();


    } 

}
早起的年轻人 CSDN认证博客专家 移动开发 项目管理 Java
只要用心去做,每一件事情还是有可能成功的,当然成功是没有界限的,只不过是达到自己心里的那个目标,公众号:我的大前端生涯,一个爱喝茶的程序员,通常会搞搞SpringBoot 、Herbinate、Mybatiys、Android、iOS、Flutter、Vue、小程序等.
©️2020 CSDN 皮肤主题: 代码科技 设计师:Amelia_0503 返回首页