背景
作为ListView
和GridView
的替代者, RecyclerView
以它的灵活性著称,而且有着更好更完善的缓存处理机制。但是在使用RecyclerVew
的过程中有个很明显的问题:RecyclerView
没有为开发者提供addHeadView
和addFooterView
两个接口,这就为RecyclerView
的下拉刷新和上拉加载实现增加了难度,本文就为大家介绍RecyclerView
的下拉刷新和上拉加载的实现方式。
下拉刷新
其实RecyclerView
的下拉刷新使用SwipeRefreshLayout
组件实现还是非常简单的。
SwipeRefreshLayout
也是Android SDK
中为我们提供的一个布局容器类,它作为容器可以为它的子元素提供下拉刷新接口,而且使用方式也非常简单,我就直接上代码了1
2
3
4
5
6
7
8
9
10
11
12<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>
这就是RecyclerView
结合SwipeRefreshLayout
实现下拉刷新的布局方式,非常简单吧,写完布局文件之后,当然还要处理刷新的逻辑1
2
3
4
5
6mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
//在此处实现刷新获取数据,然后更新RecyclerView的数据源即可
}
});
写完这两段代码之后,RecyclerView
的下拉刷新就实现完成了,是不是很简单。不过还有个小小的问题需要注意下,那就是在刷新获取数据处理逻辑结束之后需要调用1
mSwipeRefreshLayout.setRefreshing(false);
这个接口就是告诉SwipRefreshLayout
刷新动作已经结束,刷新进度条可以不用再显示了,否则的话视图顶部的刷新进度条会一直存在,当然如果你手动调用1
mSwipeRefreshLayout.setRefreshing(true);
这个接口的话,刷新进度条就会显示出来。
上拉加载
由于RecyclerView
中没有提供addFooterView
接口,所以我们没有办法像ListView
中那样直接添加一个FooterView
作为上拉加载的视图。但是RecyclerView.Adapter
中也提供了public int getItemViewType(int position)
接口,我们可以为RecyclerView.Adapter
指定两种ViewType
,一个作为普通的ItemViewType
用来显示普通数据视图,一个作为FooterViewType
用来显示上拉加载视图,这样的话我们就需要在展示数据的基础上为RecyclerView.Adapter
额外增加一条数据用来显示添加的FooterView
,这个特定Adapter
的实现逻辑如下:
定义两个
ViewType
分表用来区分普通是数据视图和上拉加载视图1
2private static final int VIEW_TYPE_FOOTER = 0;
private static final int VIEW_TYPE_ITEM = 1;重写
getItemCount()
方法,在原有数据的基础上增加一条数据用来显示FooterView
1
2
3
4
5@Override
public int getItemCount() {
return mList.size() + 1;//在原有数据的基础增加一个数据用来显示FooterView
}重写
getItemViewType(int position)
方法,用来判断当前加载显示何种视图1
2
3
4
5
6
7
8@Override
public int getItemViewType(int position) {
if(position + 1 == getItemCount()) {//最后一条数据显示FooterView
return VIEW_TYPE_FOOTER;
}
return VIEW_TYPE_ITEM;
}在
onCreateViewHolder
方法中根据viewType
初始化对应的视图1
2
3
4
5
6
7
8
9
10@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if(viewType == VIEW_TYPE_FOOTER) {
return onCreateFooterViewHolder(parent, viewType);
} else if(viewType == VIEW_TYPE_ITEM) {
return onCreateItemViewHolder(parent, viewType);
}
return null;
}在
onBindViewHolder
方法中根据viewType
绑定显示对应的视图数据1
2
3
4
5
6
7
8
9
10
11
12
13
14@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
switch (getItemViewType(position)) {
case VIEW_TYPE_ITEM:
onBindItemViewHolder(holder, position);
break;
case VIEW_TYPE_FOOTER:
onBindFooterViewHolder(holder, position, mLoadStatus);
break;
default:
break;
}
}
整个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
146public class DemoAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private LoadStatus mLoadStatus = LoadStatus.CLICK_LOAD_MORE;//上拉加载的状态
private static final int VIEW_TYPE_FOOTER = 0;
private static final int VIEW_TYPE_ITEM = 1;
private List<String> mList;
private Context mContext;
public DemoAdapter(Context context, List<String> list) {
mContext = context;
mList = list;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if(viewType == VIEW_TYPE_FOOTER) {
return onCreateFooterViewHolder(parent, viewType);
} else if(viewType == VIEW_TYPE_ITEM) {
return onCreateItemViewHolder(parent, viewType);
}
return null;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
switch (getItemViewType(position)) {
case VIEW_TYPE_ITEM:
onBindItemViewHolder(holder, position);
break;
case VIEW_TYPE_FOOTER:
onBindFooterViewHolder(holder, position, mLoadStatus);
break;
default:
break;
}
}
public RecyclerView.ViewHolder onCreateFooterViewHolder(ViewGroup parent, int viewType) {
View view = View.inflate(mContext, R.layout.footer_layout, null);
return new FooterViewHolder(view);
}
public RecyclerView.ViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType) {
View view = View.inflate(mContext, R.layout.item_layout, null);
return new ItemViewHolder(view);
}
public void onBindFooterViewHolder(RecyclerView.ViewHolder holder, int position, LoadStatus loadStatus) {
FooterViewHolder viewHolder = (FooterViewHolder) holder;
switch (loadStatus) {
case CLICK_LOAD_MORE:
viewHolder.mLoadingLayout.setVisibility(View.GONE);
viewHolder.mClickLoad.setVisibility(View.VISIBLE);
break;
case LOADING_MORE:
viewHolder.mLoadingLayout.setVisibility(View.VISIBLE);
viewHolder.mClickLoad.setVisibility(View.GONE);
break;
}
}
public void onBindItemViewHolder(RecyclerView.ViewHolder holder, int position) {
ItemViewHolder viewHolder = (ItemViewHolder) holder;
viewHolder.mTextView.setText(getItem(position));
}
@Override
public int getItemCount() {
return mList.size() + 1;
}
public String getItem(int position) {
return mList.get(position);
}
public void addAll(List<String> list) {
this.mList.addAll(list);
notifyDataSetChanged();
}
@Override
public int getItemViewType(int position) {
if(position + 1 == getItemCount()) {//最后一条为FooterView
return VIEW_TYPE_FOOTER;
}
return VIEW_TYPE_ITEM;
}
public void reSetData(List<String> list) {
this.mList = list;
notifyDataSetChanged();
}
public void setLoadStatus(LoadStatus loadStatus) {
this.mLoadStatus = loadStatus;
}
}
public class ItemViewHolder extends RecyclerView.ViewHolder {
public TextView mTextView;
public ItemViewHolder(View itemView) {
super(itemView);
mTextView = (TextView) itemView.findViewById(R.id.textView);
}
}
public class FooterViewHolder extends RecyclerView.ViewHolder {
public LinearLayout mLoadingLayout;
public TextView mClickLoad;
public FooterViewHolder(View itemView) {
super(itemView);
mLoadingLayout = (LinearLayout) itemView.findViewById(R.id.loading);
mClickLoad = (TextView) itemView.findViewById(R.id.click_load_txt);
mClickLoad.setOnClickListener(new View.OnClickListener() {//添加点击加载更多监听
@Override
public void onClick(View v) {
loadMore();
}
});
}
}
public enum LoadStatus {
CLICK_LOAD_MORE,//点击加载更多
LOADING_MORE//正在加载更多
}
FooterView
的布局如下: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<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="40dp"
android:gravity="center_horizontal"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/loading"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="match_parent"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:text="正在加载..."/>
</LinearLayout>
<TextView
android:id="@+id/click_load_txt"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:text="点击加载更多"
android:visibility="gone"/>
</RelativeLayout>
- 写完
Adapter
的FooterView
视图适配之后,我们还有一个重要的步骤需要做,在哪里实现加载更多的逻辑处理
其实RecyclerView
也为我们提供了mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() )
接口,这样我们就看一看通过这个接口来判断什么时候调用加载更多的实现接口,关键代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE
&& mLastVisibleItemPosition + 1 == mAdapter.getItemCount()) {
loadMore();
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
mLastVisibleItemPosition = mLayoutManager.findLastVisibleItemPosition();
}
});
整个Demo
的Activity
的实现如下: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
107public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private SwipeRefreshLayout mSwipeRefreshLayout;
private DemoAdapter mAdapter;
private int mLastVisibleItemPosition = 0;
private LinearLayoutManager mLayoutManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mAdapter = new DemoAdapter(this, getData("init"));
mRecyclerView.setAdapter(mAdapter);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
new Thread() {
@Override
public void run() {
try {
Thread.sleep(3000);
final List<String> list = getData("refresh");
runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.reSetData(list);
mSwipeRefreshLayout.setRefreshing(false);
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
});
mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE
&& mLastVisibleItemPosition + 1 == mAdapter.getItemCount()) {
loadMore();
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
mLastVisibleItemPosition = mLayoutManager.findLastVisibleItemPosition();
}
});
}
public void loadMore() {
mAdapter.setLoadStatus(LoadStatus.LOADING_MORE);
new Thread() {
@Override
public void run() {
try {
Thread.sleep(3000);
final List<String> list = getData("load more");
runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.addAll(list);
mAdapter.setLoadStatus(LoadStatus.CLICK_LOAD_MORE);
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
public List<String> getData(String flag) {
int idx = 1;
if(mAdapter != null) {
idx = mAdapter.getItemCount();
}
List<String> list = new ArrayList<>(10);
for(int i = 0; i < 10; i++) {
list.add(flag + ":" + (idx + i));
}
return list;
}
}
以上就是我针对RecyclerView
的下拉刷新上拉加载的实现方式。
原创文章,转载请出处注明。
下面是我的个人公众号,欢迎关注交流