SwipeRefreshLayout+RecycleView实现下拉刷新上拉加载

此文是根据我自己的使用总结,至于RecyclerView的具体使用就不多做介绍,想要了解网上一大堆。

比较推荐这篇:

RecyclerView 使用完全解析 体验艺术般的控件

  • 下拉刷新

使用SwipeRefreshLayout妥妥的,窗口中继承SwipeRefreshLayout.OnRefreshListener即可实现下拉刷新效果

  • 上拉加载

上拉加载中按照需求,我们需要一个刷新进度条的Item提示,所以需要自定义RecyclerView的适配器,来添加底部进度条的Item,代码如下:

FooterViewRecyclerAdapter.java

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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* 自定义一个适配器,为recycleview添加,列表头部和尾部Item
* Created by yanjie.xu on 2017/9/10.
*/
public class FooterViewRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final String TAG = "FooterViewRecyclerAdapter";

private static final int HEADERS_START = Integer.MIN_VALUE;
private static final int FOOTERS_START = Integer.MIN_VALUE + 10;
private static final int ITEMS_START = Integer.MIN_VALUE + 20;
private static final int ADAPTER_MAX_TYPES = 100;

private RecyclerView.Adapter mWrappedAdapter;
private List<View> mHeaderViews, mFooterViews;
private Map<Class, Integer> mItemTypesOffset;

/**
* 构造一个新的标题视图回收器适配器
*
* @param 适配器要包装的底层适配器
*/
public FooterViewRecyclerAdapter(RecyclerView.Adapter adapter) {
mHeaderViews = new ArrayList<View>();
mFooterViews = new ArrayList<View>();
mItemTypesOffset = new HashMap<Class, Integer>();
setWrappedAdapter(adapter);
}

/**
* 替换底层适配器,通知RecyclerView更改
*
* @param 新的适配器包装
*/
public void setAdapter(RecyclerView.Adapter adapter) {
if (mWrappedAdapter != null && mWrappedAdapter.getItemCount() > 0) {
notifyItemRangeRemoved(getHeaderCount(), mWrappedAdapter.getItemCount());
}
setWrappedAdapter(adapter);
notifyItemRangeInserted(getHeaderCount(), mWrappedAdapter.getItemCount());
}

@Override
public int getItemViewType(int position) {
int hCount = getHeaderCount();
if (position < hCount) return HEADERS_START + position;
else {
int itemCount = mWrappedAdapter.getItemCount();
if (position < hCount + itemCount) {
return getAdapterTypeOffset() + mWrappedAdapter.getItemViewType(position - hCount);
} else return FOOTERS_START + position - hCount - itemCount;
}
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
if (viewType < HEADERS_START + getHeaderCount())
return new StaticViewHolder(mHeaderViews.get(viewType - HEADERS_START));
else if (viewType < FOOTERS_START + getFooterCount())
return new StaticViewHolder(mFooterViews.get(viewType - FOOTERS_START));
else {
return mWrappedAdapter.onCreateViewHolder(viewGroup, viewType - getAdapterTypeOffset());
}
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
int hCount = getHeaderCount();
if (position >= hCount && position < hCount + mWrappedAdapter.getItemCount())
mWrappedAdapter.onBindViewHolder(viewHolder, position - hCount);
}

/**
* 添加一个静态视图,显示在RecyclerView的开头。 标题按照添加的顺序显示。
*
* @param view要添加的标题视图
*/
public void addHeaderView(View view) {
mHeaderViews.add(view);
}

/**
* 添加静态视图以显示在RecyclerView的末尾。 页脚按照添加的顺序显示。
*
* @param view要添加的页脚视图
*/
public void addFooterView(View view) {
mFooterViews.add(view);
}

@Override
public int getItemCount() {
return getHeaderCount() + getFooterCount() + getWrappedItemCount();
}

/**
* @return 底层适配器中的项目计数
*/
public int getWrappedItemCount() {
return mWrappedAdapter.getItemCount();
}

/**
* @return 添加标题视图的数量
*/
public int getHeaderCount() {
return mHeaderViews.size();
}

/**
* @return 添加了页脚视图的数量
*/
public int getFooterCount() {
return mFooterViews.size();
}

private void setWrappedAdapter(RecyclerView.Adapter adapter) {
if (mWrappedAdapter != null) mWrappedAdapter.unregisterAdapterDataObserver(mDataObserver);
mWrappedAdapter = adapter;
Class adapterClass = mWrappedAdapter.getClass();
if (!mItemTypesOffset.containsKey(adapterClass)) putAdapterTypeOffset(adapterClass);
mWrappedAdapter.registerAdapterDataObserver(mDataObserver);
}

private void putAdapterTypeOffset(Class adapterClass) {
mItemTypesOffset.put(adapterClass, ITEMS_START + mItemTypesOffset.size() * ADAPTER_MAX_TYPES);
}

private int getAdapterTypeOffset() {
return mItemTypesOffset.get(mWrappedAdapter.getClass());
}

private RecyclerView.AdapterDataObserver mDataObserver = new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
super.onChanged();
notifyDataSetChanged();
}

@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
super.onItemRangeChanged(positionStart, itemCount);
notifyItemRangeChanged(positionStart + getHeaderCount(), itemCount);
}

@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
super.onItemRangeInserted(positionStart, itemCount);
notifyItemRangeInserted(positionStart + getHeaderCount(), itemCount);
}

@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
super.onItemRangeRemoved(positionStart, itemCount);
notifyItemRangeRemoved(positionStart + getHeaderCount(), itemCount);
}

@Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
super.onItemRangeMoved(fromPosition, toPosition, itemCount);
int hCount = getHeaderCount();
// TODO: No notifyItemRangeMoved method?
notifyItemRangeChanged(fromPosition + hCount, toPosition + hCount + itemCount);
}
};

/**
* 移除页脚加载选项
*/
public void removeFooterView(){
mFooterViews.clear();
notifyDataSetChanged();
}

/**
* 获取footer总数
* @return
*/
public int footerViewCount(){
return mFooterViews.size();
}

private static class StaticViewHolder extends RecyclerView.ViewHolder {
public StaticViewHolder(View itemView) {
super(itemView);
}
}
}

通过上面的适配器,我们可以给自己的RecyclerView添加一个上拉加载进度条的Item,用户上拉显示这个加载提示Item,然后程序就去操作数据的加载和刷新,RecycleView中没有我们需要的显示最后一项Item的监听,这需要我们自己创造

EndlessRecyclerOnScrollListener.java

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
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

/**
* RecyclerView滑动监听类
* 封装加载更多的接口实现类,作为参数传递。
*
* Created by yanjie.xu on 2017/9/19.
*/
public abstract class EndlessRecyclerOnScrollListener extends
RecyclerView.OnScrollListener {

private int previousTotal = 0;
private boolean loading = true;
//list计数器
int firstVisibleItem, visibleItemCount, totalItemCount;

private int currentPage = 1;

private LinearLayoutManager mLinearLayoutManager;

public EndlessRecyclerOnScrollListener(LinearLayoutManager linearLayoutManager) {
this.mLinearLayoutManager = linearLayoutManager;
}

@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);

visibleItemCount = recyclerView.getChildCount();
totalItemCount = mLinearLayoutManager.getItemCount();
firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition();

if (loading) {
if (totalItemCount - previousTotal != 0/*totalItemCount > previousTotal*/) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading
&& (totalItemCount - visibleItemCount) <= firstVisibleItem) {
currentPage++;
onLoadMore(currentPage);
loading = true;
}
}

public abstract void onLoadMore(int currentPage);
}

一切工具和适配都准备好了,下面我们开始干活

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
// listView 及其 适配器绑定、事件监听
mRecyclerView = (RecyclerView) view.findViewById(R.id.fragment_contacts_list);
//设置布局管理器
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
mRecyclerView.setLayoutManager(layoutManager);
//创建适配器
mDataAdapter = new ContactListAdapter(getContext());
//创建一个可添加尾部头部布局的RecycleViewAdapter
mHeaderAdapter = new FooterViewRecyclerAdapter(mDataAdapter);
//设置adapter
mRecyclerView.setAdapter(mHeaderAdapter);
createLoadMoreView();
//设置点击事件监听器
mDataAdapter.setOnItemClickLitener(this);
//设置滚动监听器
mRecyclerView.setOnScrollListener(new EndlessRecyclerOnScrollListener(layoutManager) {
@Override
public void onLoadMore(int currentPage) {
loadMore(currentPage);
}
});

//设置Item增加、移除动画
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
//添加分割线
//recyclerView.addItemDecoration(new DividerItemDecoration(
//getActivity(), DividerItemDecoration.HORIZONTAL_LIST));

这主要的使用代码片段,我们具体的加载更多放在loadMore(int currentPage)方法中

而FooterViewRecyclerAdapter和我们的数据列表的RecyclerViewAdapter完全解耦,不会有任何影响