RecycleView分页加载

时间:2024-04-14 07:41:07

在开发中常常使用到刷新分页,这里实现一个 RecyclerView 的简单的刷新分页操作,RecyclerView 的刷新分页会了,相信 ListView 、ExpandListView 分组列表的刷新分页肯定不在话下,那就一起来看一下具体是如何实现的。

实现思路

  1. 加载更多数据使用到 RecyclerView 加载多种布局,根据 ViewType 判断加载数据 Item 还是加载 FooterItem ;

  2. 通过线程模拟加载数据;

  3. 为 RecyclerView 添加滚动事件来监听用户的滑动操作;

  4. 根据用户滑动状态以及具体情况开始加载数据

  5. 通知数据更新。

遇到的第一个问题肯定就是如何获得屏幕上第一个可见的 Item 呢?为了能够在数据加载中动态判断什么时候加载数据,需要知道屏幕上显示的第一个可见的 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。

准备数据

这里使用线程模拟网络数据,直接看代码,具体如下:

 

1    /**
2     * 初始化数据
3     * @return
4     */
5    public void  initData(){
6        for (int i=0;i<30;i++){
7            arrayList.add("第"+i+"条数据");
8        }
9    }
10
11    /**
12     * 线程模拟加载数据
13     */
14    class LoadDataThread extends Thread{
15        @Override
16        public void run() {
17            initData();
18            try {
19                Thread.sleep(2000);
20            } catch (InterruptedException e) {
21                e.printStackTrace();
22            }
23            //通知主线程更新数据
24            Message message = handler.obtainMessage();
25            message.what = UPDATE_DATA;
26            message.obj = arrayList;
27            handler.sendMessage(message);
28        }
29    }

代码参考

一直觉得写博客如果没有源码链接,最好把代码补全,希望每一个读者都能有所收获。

主要布局

 

1<?xml version="1.0" encoding="utf-8"?>
2<LinearLayout
3    xmlns:android="http://schemas.android.com/apk/res/android"
4    xmlns:tools="http://schemas.android.com/tools"
5    android:layout_width="match_parent"
6    android:layout_height="match_parent"
7    tools:context="com.manu.mrecyclerview.MainActivity">
8    <android.support.v7.widget.RecyclerView
9        android:id="@+id/rv"
10        android:layout_width="match_parent"
11        android:layout_height="match_parent">
12    </android.support.v7.widget.RecyclerView>
13</LinearLayout>

Item 布局

RecyclerView 每一数据项的布局,具体如下:

 

1/**item.xml**/
2<?xml version="1.0" encoding="utf-8"?>
3<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
4    android:orientation="vertical"
5    android:layout_width="match_parent"
6    android:layout_height="match_parent"
7    android:padding="5dp">
8    <TextView
9        android:id="@+id/tv_recycle"
10        android:layout_width="match_parent"
11        android:layout_height="wrap_content"
12        android:gravity="center_horizontal"
13        android:text="data"
14        android:background="#cac3c3"
15        android:padding="10dp"
16        android:textSize="20sp"/>
17</LinearLayout>

Footer 布局

Footer 布局作为加载更多的布局,具体如下:

 

1/**item_footer.xml**/
2<?xml version="1.0" encoding="utf-8"?>
3<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
4    android:orientation="horizontal"
5    android:layout_width="match_parent"
6    android:layout_height="match_parent"
7    android:gravity="center_horizontal">
8    <ProgressBar
9        style="?android:attr/progressBarStyleSmall"
10        android:layout_width="wrap_content"
11        android:layout_height="wrap_content"
12        android:id="@+id/progressBar" />
13    <TextView
14        android:text="正在努力加载中,请稍后..."
15        android:layout_width="wrap_content"
16        android:layout_height="wrap_content"
17        android:id="@+id/textView" />
18</LinearLayout>

Adapter

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

 

 1/**
 2 * Created by jzman on 2017/6/04
 3 * RecycleView的Adapter
 4 */
 5public class RvAdapter1 extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements
 6        View.OnClickListener{
 7    private static final int ITEM_FOOTER = 0x1;
 8    private static final int ITEM_DATA = 0x2;
 9    private Context mContext;
10    private RecyclerView recyclerView;
11    private ArrayList<String> mList;
12
13    public RvAdapter1() {}
14
15    public RvAdapter1(Context mContext, ArrayList<String> mList) {
16        this.mContext = mContext;
17        this.mList = mList;
18    }
19
20    public void setmList(ArrayList<String> mList) {
21        this.mList = mList;
22    }
23
24    /**
25     * 用于创建ViewHolder
26     * @param parent
27     * @param viewTypez
28     * @return
29     */
30    @Override
31    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
32        View view ;
33        RecyclerView.ViewHolder vh = null;
34        switch (viewType){
35            case ITEM_DATA:
36                view = LayoutInflater.from(mContext).inflate(R.layout.item,null);
37                view.setOnClickListener(this);
38                vh = new DataViewHolder(view);
39                //使用代码设置宽高(xml布局设置无效时)
40                view.setLayoutParams(new ViewGroup.LayoutParams(
41                        ViewGroup.LayoutParams.MATCH_PARENT,
42                        ViewGroup.LayoutParams.WRAP_CONTENT));
43                break;
44            case ITEM_FOOTER:
45                view = LayoutInflater.from(mContext).inflate(R.layout.item_footer,null);
46                //使用代码设置宽高(xml布局设置无效时)
47                vh = new FooterViewHolder(view);
48                view.setLayoutParams(new ViewGroup.LayoutParams(
49                        ViewGroup.LayoutParams.MATCH_PARENT,
50                        ViewGroup.LayoutParams.WRAP_CONTENT));
51                break;
52        }
53        return vh;
54    }
55
56    /**
57     * 获取Item的View类型
58     * @param position
59     * @return
60     */
61    @Override
62    public int getItemViewType(int position) {
63        //根据 Item 的 position 返回不同的 Viewtype
64        if (position == (getItemCount())-1){
65            return ITEM_FOOTER;
66        }else{
67            return ITEM_DATA;
68        }
69    }
70
71    /**
72     * 绑定数据
73     * @param holder
74     * @param position
75     */
76    @Override
77    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
78        if (holder instanceof DataViewHolder){
79            DataViewHolder dataViewHolder = (DataViewHolder) holder;
80            dataViewHolder.tv_data.setText(mList.get(position));
81        }else if (holder instanceof FooterViewHolder){
82
83        }
84    }
85
86    /**
87     * 选项总数
88     * @return
89     */
90    @Override
91    public int getItemCount() {
92        return mList.size()+1;
93    }
94
95    @Override
96    public void onClick(View view) {
97        //根据RecyclerView获得当前View的位置
98        int position = recyclerView.getChildAdapterPosition(view);
99        //程序执行到此,会去执行具体实现的onItemClick()方法
100        if (onItemClickListener!=null){
101            onItemClickListener.onItemClick(recyclerView,view,position,mList.get(position));
102        }
103    }
104
105    /**
106     * 创建ViewHolder
107     */
108    public static class DataViewHolder extends RecyclerView.ViewHolder{
109        TextView tv_data;
110        public DataViewHolder(View itemView) {
111            super(itemView);
112            tv_data = (TextView) itemView.findViewById(R.id.tv_recycle);
113        }
114    }
115
116    /**
117     * 创建footer的ViewHolder
118     */
119    public static class FooterViewHolder extends RecyclerView.ViewHolder{
120        public FooterViewHolder(View itemView) {
121            super(itemView);
122        }
123    }
124
125    private OnItemClickListener onItemClickListener;
126    public void setOnItemClickListener(OnItemClickListener onItemClickListener){
127        this.onItemClickListener = onItemClickListener;
128    }
129
130    /**
131     * 定义RecyclerView选项单击事件的回调接口
132     */
133    public interface OnItemClickListener{
134        //参数(父组件,当前单击的View,单击的View的位置,数据)
135        void onItemClick(RecyclerView parent,View view, int position, String data);
136    }
137    /**
138     *   将RecycleView附加到Adapter上
139     */
140    @Override
141    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
142        super.onAttachedToRecyclerView(recyclerView);
143        this.recyclerView= recyclerView;
144    }
145    /**
146     *   将RecycleView从Adapter解除
147     */
148    @Override
149    public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
150        super.onDetachedFromRecyclerView(recyclerView);
151        this.recyclerView = null;
152    }
153}

MainActivity

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

 

 1/**
 2 * Created by jzman on 2017/6/04 0013.
 3 */
 4public class MainActivity extends AppCompatActivity {
 5    private static final int UPDATE_DATA = 0x3;
 6
 7    private RecyclerView rv;
 8    RvAdapter1 adapter;
 9
10    private ArrayList<String> arrayList = new ArrayList<>();
11    //加载更多数据时最后一项的索引
12    private int lastLoadDataItemPosition;
13
14    @Override
15    protected void onCreate(Bundle savedInstanceState) {
16        super.onCreate(savedInstanceState);
17        setContentView(R.layout.activity_main);
18        rv = (RecyclerView) findViewById(R.id.rv);
19
20        //设置布局管理器
21        rv.setLayoutManager(new LinearLayoutManager(this));//线性
22//        rv.setLayoutManager(new GridLayoutManager(this,4));//线性
23//        rv.setLayoutManager(new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.VERTICAL));//线性
24        initData();
25        adapter = new RvAdapter1(this,arrayList);
26        adapter.setOnItemClickListener(new RvAdapter1.OnItemClickListener() {
27            @Override
28            public void onItemClick(RecyclerView parent, View view, int position, String data) {
29                Toast.makeText(MainActivity.this, data, Toast.LENGTH_SHORT).show();
30            }
31        });
32
33        rv.addOnScrollListener(new OnScrollListener() {
34            @Override
35            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
36                if (newState == SCROLL_STATE_IDLE &&
37                        lastLoadDataItemPosition == adapter.getItemCount()){
38                    new LoadDataThread().start();
39                }
40            }
41
42            @Override
43            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
44
45                LayoutManager layoutManager = recyclerView.getLayoutManager();
46                if (layoutManager instanceof LinearLayoutManager){
47                    LinearLayoutManager manager = (LinearLayoutManager) layoutManager;
48                    int firstVisibleItem = manager.findFirstVisibleItemPosition();
49                    int l = manager.findLastCompletelyVisibleItemPosition();
50                    lastLoadDataItemPosition = firstVisibleItem+(l-firstVisibleItem)+1;
51                }
52            }
53        });
54
55        rv.setAdapter(adapter);
56    }
57
58    /**
59     * 初始化数据
60     * @return
61     */
62    public void  initData(){
63        for (int i=0;i<25;i++){
64            arrayList.add("第"+i+"条数据");
65        }
66    }
67
68    /**
69     * 线程模拟加载数据
70     */
71    class LoadDataThread extends Thread{
72        @Override
73        public void run() {
74            initData();
75            try {
76                Thread.sleep(2000);
77            } catch (InterruptedException e) {
78                e.printStackTrace();
79            }
80            Message message = handler.obtainMessage();
81            message.what = UPDATE_DATA;
82            message.obj = arrayList;
83            handler.sendMessage(message);
84        }
85    }
86
87    private Handler handler = new Handler(){
88
89        @Override
90        public void handleMessage(Message msg) {
91            super.handleMessage(msg);
92            switch (msg.what){
93                case UPDATE_DATA:
94                    arrayList = (ArrayList<String>) msg.obj;
95                    adapter.setmList(arrayList);
96                    adapter.notifyDataSetChanged();
97                    break;
98            }
99        }
100    };
101}

显示效果

RecycleView分页加载

RecyclerView 的刷新分页