在開發中常常使用到刷新分頁,這里實現一個 RecyclerView 的簡單的刷新分頁操作,測試效果見文末,實現過程參考如下:
實現思路
- 加載更多數據使用到 RecyclerView 加載多種布局,根據 ViewType 判斷加載數據 Item 還是加載 FooterItem ;
- 通過線程模擬加載數據;
- 為 RecyclerView 添加 addOnScrollListener 事件來監聽用戶的滑動操作;
- 根據用戶滑動狀態以及具體情況開始加載數據
- 通知數據更新;
如何獲得 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。
準備數據
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
/** * 初始化數據 * @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); } } |
代碼參考
主布局
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<? 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布局
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/**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 > |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/**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 代碼參考如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
/** * 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 代碼參考如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
/** * 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 ; } } }; } |
測試效果
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://www.jianshu.com/p/9a540babacf0