Android RecyclerView 上拉加载
01.添加recyclerView的滑动事件
首先给recyclerView添加滑动监听事件。那么我们知道,上拉加载时,需要具备两个条件。第一个是监听滑动到最后一个item,第二个是滑动到最后一个并且是向上滑动。
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// 实现上拉加载重要步骤,设置滑动监听器,RecyclerView自带的ScrollListener
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
//用来标记是否正在向上滑动
private boolean isSlidingUpward = false;
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
// 当不滑动的时候
// 在newState为滑到底部时
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
//获取最后一个完全显示的itemPosition
int lastItemPosition = layoutManager.findLastCompletelyVisibleItemPosition();
int itemCount = layoutManager.getItemCount();
//int itemCount1 = adapter.getItemCount();
// 判断是否滑动到了最后一个item,并且是向上滑动
if (lastItemPosition == (itemCount - 1) && isSlidingUpward) {
handler.postDelayed(new Runnable() {
@Override
public void run() {
updateRecyclerView(datas);
}
}, 2000);
}
}
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// 大于0表示正在向上滑动,小于等于0表示停止或向下滑动
isSlidingUpward = dy > 0;
}
});
02.上拉加载分页数据
然后看一下updateRecyclerView的方法。注意这里的刷新数据,可以直接用notifyItemRangeInserted方法,不要用notifyDataSetChanged方法。
1
2
3
4
5
6
7
8
9
10
11
12/**
* 暴露接口,更新数据源,并修改hasMore的值,如果有增加数据,hasMore为true,否则为false
*/
public void updateList(List<PersonData> newDatas, boolean hasMore) {
int size = data.size();
// 在原有的数据之上增加新数据
if (newDatas != null) {
data.addAll(newDatas);
this.hasMore = hasMore;
notifyItemRangeInserted(size,newDatas.size());
}
}
03.设置上拉加载的底部footer布局
如下所示,核心代码
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@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// 根据返回的ViewType,绑定不同的布局文件,这里只有两种
if (viewType == normalType) {
return new MyViewHolder(LayoutInflater.from(mContext)
.inflate(R.layout.item_news, parent,false));
} else {
//这个是上拉加载更多的view
return new FootHolder(LayoutInflater.from(mContext)
.inflate(R.layout.view_more, parent,false));
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (holder instanceof MyViewHolder){
PersonData person = data.get(position);
setBindViewHolder((MyViewHolder)holder,person,position);
}else {
setFootBindViewHolder((FootHolder)holder ,position);
}
}
/**
* 获取条目数量,之所以要加1是因为增加了一条footView
*/
@Override
public int getItemCount() {
return data == null ? 0 : data.size()+1;
}
/**
* 根据条目位置返回ViewType,以供onCreateViewHolder方法内获取不同的Holder
*/
@Override
public int getItemViewType(int position) {
if (position == getItemCount() - 1) {
return footType;
} else {
return normalType;
}
}
04.显示和隐藏footer布局
一般情况下,滑动底部最后一个item,然后显示footer上拉加载布局,然后让其加载500毫秒,最后加载出下一页数据后再隐藏起来。
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
31private void setFootBindViewHolder(final FootHolder holder, int position) {
// 之所以要设置可见,是因为我在没有更多数据时会隐藏了这个footView
holder.tv_more.setVisibility(View.VISIBLE);
// 只有获取数据为空时,hasMore为false,所以当我们拉到底部时基本都会首先显示“正在加载更多...”
if (hasMore) {
// 不隐藏footView提示
fadeTips = false;
if (data.size() > 0) {
// 如果查询数据发现增加之后,就显示正在加载更多
holder.tv_more.setText("逗比,正在加载更多...");
}
} else {
if (data.size() > 0) {
// 如果查询数据发现并没有增加时,就显示没有更多数据了
holder.tv_more.setText("逗比,没有更多数据了");
// 然后通过延时加载模拟网络请求的时间,在500ms后执行
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
// 隐藏提示条
holder.tv_more.setVisibility(View.GONE);
// 将fadeTips设置true
fadeTips = true;
// hasMore设为true是为了让再次拉到底时,会先显示正在加载更多
hasMore = true;
}
}, 500);
}
}
}