RecyclerView的刷新分页

作者: 躬行之 | 来源:发表于2018-05-19 20:12 被阅读85次

    在开发中常常使用到刷新分页,这里实现一个 RecyclerView 的简单的刷新分页操作,测试效果见文末,实现过程参考如下:

    实现思路

    1. 加载更多数据使用到 RecyclerView 加载多种布局,根据 ViewType 判断加载数据 Item 还是加载 FooterItem ;
    2. 通过线程模拟加载数据;
    3. 为 RecyclerView 添加 addOnScrollListener 事件来监听用户的滑动操作;
    4. 根据用户滑动状态以及具体情况开始加载数据
    5. 通知数据更新;

    如何获得 firstVisibleItemPosition

    为了能够在数据加载中动态判断什么时候加载数据,需要知道屏幕上显示的第一个可见的 Item 的位置,当然了这里使用的是布局管理器是 LinearLayoutManager ,这样查找屏幕上第一个可见的 Item 就显得容易多了,下面介绍一些 LinearLayoutManager 的四个方法:

    findFirstVisibleItemPosition()

    获得屏幕上第一个可见 Item 的 position,只要该 Item 有一部分可见,那么返回的 position 就是该Item 的 position。

    findFirstCompletelyVisibleItemPosition()

    获得屏幕上第一个完整可见的 Item 的 position,只要该 Item 有一部分不可见,那么返回的 position 就是该 Item 对应的下一个能显示完整的 Item 的position。

    findLastVisibleItemPosition()

    获得屏幕上最后一个可见 Item 的 position,只要该 Item 有一部分可见,那么返回的 position 就是该Item 的 position。

    findLastCompletelyVisibleItemPosition()

    获得屏幕上最后一个完整可见的 Item 的 position,只要该 Item 有一部分不可见,那么返回的 position 就是该 Item 对应的上一个能显示完整的 Item 的position。

    准备数据

        /**
         * 初始化数据
         * @return
         */
        public void  initData(){
            for (int i=0;i<30;i++){
                arrayList.add("第"+i+"条数据");
            }
        }
        
        /**
         * 线程模拟加载数据
         */
        class LoadDataThread extends Thread{
            @Override
            public void run() {
                initData();
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //通知主线程更新数据
                Message message = handler.obtainMessage();
                message.what = UPDATE_DATA;
                message.obj = arrayList;
                handler.sendMessage(message);
            }
        }
    

    代码参考

    主布局

    
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.manu.mrecyclerview.MainActivity">
        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        </android.support.v7.widget.RecyclerView>
    </LinearLayout>
    
    

    Item布局

    /**item.xml**/
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="5dp">
        <TextView
            android:id="@+id/tv_recycle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:text="data"
            android:background="#cac3c3"
            android:padding="10dp"
            android:textSize="20sp"/>
    </LinearLayout>
    
    

    /**item_footer.xml**/
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal">
        <ProgressBar
            style="?android:attr/progressBarStyleSmall"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/progressBar" />
        <TextView
            android:text="正在努力加载中,请稍后..."
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/textView" />
    </LinearLayout>
    
    

    Adapter

    这里使用了 RecyclerView 根据不同的 ViewType 加载多种布局的用法,使用时根据不同的布局创建不同的 ViewHolder , 然后根据不同的 Viewholder 为对应的 Item 添加数据,注意 getItemViewType() 方法的用法,Adapter 代码参考如下:

    /**
     * Created by jzman on 2017/6/04
     * RecycleView的Adapter
     */
    public class RvAdapter1 extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements
            View.OnClickListener{
        private static final int ITEM_FOOTER = 0x1;
        private static final int ITEM_DATA = 0x2;
        private Context mContext;
        private RecyclerView recyclerView;
        private ArrayList<String> mList;
    
        public RvAdapter1() {}
    
        public RvAdapter1(Context mContext, ArrayList<String> mList) {
            this.mContext = mContext;
            this.mList = mList;
        }
    
        public void setmList(ArrayList<String> mList) {
            this.mList = mList;
        }
    
        /**
         * 用于创建ViewHolder
         * @param parent
         * @param viewTypez
         * @return
         */
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view ;
            RecyclerView.ViewHolder vh = null;
            switch (viewType){
                case ITEM_DATA:
                    view = LayoutInflater.from(mContext).inflate(R.layout.item,null);
                    view.setOnClickListener(this);
                    vh = new DataViewHolder(view);
                    //使用代码设置宽高(xml布局设置无效时)
                    view.setLayoutParams(new ViewGroup.LayoutParams(
                            ViewGroup.LayoutParams.MATCH_PARENT,
                            ViewGroup.LayoutParams.WRAP_CONTENT));
                    break;
                case ITEM_FOOTER:
                    view = LayoutInflater.from(mContext).inflate(R.layout.item_footer,null);
                    //使用代码设置宽高(xml布局设置无效时)
                    vh = new FooterViewHolder(view);
                    view.setLayoutParams(new ViewGroup.LayoutParams(
                            ViewGroup.LayoutParams.MATCH_PARENT,
                            ViewGroup.LayoutParams.WRAP_CONTENT));
                    break;
            }
            return vh;
        }
    
        /**
         * 获取Item的View类型
         * @param position
         * @return
         */
        @Override
        public int getItemViewType(int position) {
            //根据 Item 的 position 返回不同的 Viewtype
            if (position == (getItemCount())-1){
                return ITEM_FOOTER;
            }else{
                return ITEM_DATA;
            }
        }
    
        /**
         * 绑定数据
         * @param holder
         * @param position
         */
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
            if (holder instanceof DataViewHolder){
                DataViewHolder dataViewHolder = (DataViewHolder) holder;
                dataViewHolder.tv_data.setText(mList.get(position));
            }else if (holder instanceof FooterViewHolder){
    
            }
        }
    
        /**
         * 选项总数
         * @return
         */
        @Override
        public int getItemCount() {
            return mList.size()+1;
        }
    
        @Override
        public void onClick(View view) {
            //根据RecyclerView获得当前View的位置
            int position = recyclerView.getChildAdapterPosition(view);
            //程序执行到此,会去执行具体实现的onItemClick()方法
            if (onItemClickListener!=null){
                onItemClickListener.onItemClick(recyclerView,view,position,mList.get(position));
            }
        }
    
        /**
         * 创建ViewHolder
         */
        public static class DataViewHolder extends RecyclerView.ViewHolder{
            TextView tv_data;
            public DataViewHolder(View itemView) {
                super(itemView);
                tv_data = (TextView) itemView.findViewById(R.id.tv_recycle);
            }
        }
    
        /**
         * 创建footer的ViewHolder
         */
        public static class FooterViewHolder extends RecyclerView.ViewHolder{
            public FooterViewHolder(View itemView) {
                super(itemView);
            }
        }
    
        private OnItemClickListener onItemClickListener;
        public void setOnItemClickListener(OnItemClickListener onItemClickListener){
            this.onItemClickListener = onItemClickListener;
        }
    
        /**
         * 定义RecyclerView选项单击事件的回调接口
         */
        public interface OnItemClickListener{
            //参数(父组件,当前单击的View,单击的View的位置,数据)
            void onItemClick(RecyclerView parent,View view, int position, String data);
        }
        /**
         *   将RecycleView附加到Adapter上
         */
        @Override
        public void onAttachedToRecyclerView(RecyclerView recyclerView) {
            super.onAttachedToRecyclerView(recyclerView);
            this.recyclerView= recyclerView;
        }
        /**
         *   将RecycleView从Adapter解除
         */
        @Override
        public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
            super.onDetachedFromRecyclerView(recyclerView);
            this.recyclerView = null;
        }
    }
    
    

    MainActivity

    这里主要注意 rv.addOnScrollListener(new OnScrollListener() ...里面的具体实现,MainActivity 代码参考如下:

    /**
     * Created by jzman on 2017/6/04 0013.
     */
    public class MainActivity extends AppCompatActivity {
        private static final int UPDATE_DATA = 0x3;
        
        private RecyclerView rv;
        RvAdapter1 adapter;
    
        private ArrayList<String> arrayList = new ArrayList<>();
        //加载更多数据时最后一项的索引
        private int lastLoadDataItemPosition;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            rv = (RecyclerView) findViewById(R.id.rv);
    
            //设置布局管理器
            rv.setLayoutManager(new LinearLayoutManager(this));//线性
    //        rv.setLayoutManager(new GridLayoutManager(this,4));//线性
    //        rv.setLayoutManager(new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.VERTICAL));//线性
            initData();
            adapter = new RvAdapter1(this,arrayList);
            adapter.setOnItemClickListener(new RvAdapter1.OnItemClickListener() {
                @Override
                public void onItemClick(RecyclerView parent, View view, int position, String data) {
                    Toast.makeText(MainActivity.this, data, Toast.LENGTH_SHORT).show();
                }
            });
    
            rv.addOnScrollListener(new OnScrollListener() {
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    if (newState == SCROLL_STATE_IDLE &&
                            lastLoadDataItemPosition == adapter.getItemCount()){
                        new LoadDataThread().start();
                    }
                }
    
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    
                    LayoutManager layoutManager = recyclerView.getLayoutManager();
                    if (layoutManager instanceof LinearLayoutManager){
                        LinearLayoutManager manager = (LinearLayoutManager) layoutManager;
                        int firstVisibleItem = manager.findFirstVisibleItemPosition();
                        int l = manager.findLastCompletelyVisibleItemPosition();
                        lastLoadDataItemPosition = firstVisibleItem+(l-firstVisibleItem)+1;
                    }
                }
            });
    
            rv.setAdapter(adapter);
        }
    
        /**
         * 初始化数据
         * @return
         */
        public void  initData(){
            for (int i=0;i<25;i++){
                arrayList.add("第"+i+"条数据");
            }
        }
    
        /**
         * 线程模拟加载数据
         */
        class LoadDataThread extends Thread{
            @Override
            public void run() {
                initData();
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Message message = handler.obtainMessage();
                message.what = UPDATE_DATA;
                message.obj = arrayList;
                handler.sendMessage(message);
            }
        }
    
        private Handler handler = new Handler(){
    
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what){
                    case UPDATE_DATA:
                        arrayList = (ArrayList<String>) msg.obj;
                        adapter.setmList(arrayList);
                        adapter.notifyDataSetChanged();
                        break;
                }
            }
        };
    }
    
    

    测试效果

    jzman-blog

    可关注微信公众号:jzman-blog 获取最新文章更新,一起交流学习!

    jzman-blog

    相关文章

      网友评论

        本文标题:RecyclerView的刷新分页

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