RecyclerView上拉加载更多
为什么要写这个呢,因为RecyclerView的上拉加载不像ListView通过添加FooterView那么方便,很多通过addScrollListener的方式实现的太繁琐,需要添加各种标识,需要交互联动。
不想说废话了,最好的不是好的,适合的才是最好的,代码如下:
public abstract class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Object> items;
protected Context context;
private boolean isLoading;//是否正在加载
private boolean hasLoadMore;//是否有加载更多,判断依据是如果增加的条目小于 aPageCount,那么就没有了
private int aPageCount = 10;//每一页多少个,默认10,可根据后台返回的实际情况调节
private OnLoadMoreListener loadMoreListener;
private int currPage = 1;//当前加载的页标
private final int TYPE_ITEM = 0, TYPE_FOOTER = 1;
public MyAdapter(List<? extends Object> items, Context context) {
if (items != null) {
this.items = new ArrayList<>();
this.items.addAll(items);
}
this.context = context;
}
public MyAdapter(List<? extends Object> items, Context context, int aPageCount) {
if (items != null) {
this.items = new ArrayList<>();
this.items.addAll(items);
}
this.context = context;
this.aPageCount = aPageCount;
}
public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
public void notifyDataSetAndRefresh(List<? extends Object> data) {
if (items == null) {
items = new ArrayList<>();
} else {
items.clear();
}
currPage = 1;
hasLoadMore = false;
if (data != null) {
if (data.size() >= aPageCount) {
hasLoadMore = true;
}
items.addAll(data);
}
super.notifyDataSetChanged();
isLoading = false;
}
public void notifyDataSetAndAdd(List<? extends Object> data) {
if (items == null) items = new ArrayList<>();
hasLoadMore = false;
if (data != null) {
if (data.size() >= aPageCount) {
hasLoadMore = true;
}
items.addAll(data);
if (loadMoreListener == null) {
super.notifyItemRangeInserted(items.size() - data.size(), data.size());
} else {
super.notifyItemRangeChanged(items.size() - data.size(), data.size() + 1);
}
isLoading = false;
}
}
public abstract void onBindItemData(RecyclerView.ViewHolder holder, Object itemBean);
public abstract RecyclerView.ViewHolder getItemViewHolder(ViewGroup parent, int viewType);
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == TYPE_FOOTER) {
return new MyFooterViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_loadmore, parent, false));
}
return getItemViewHolder(parent, viewType);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
int itemViewType = getItemViewType(position);
if (itemViewType == TYPE_FOOTER) {
MyFooterViewHolder footerViewHolder = (MyFooterViewHolder) holder;
footerViewHolder.refreshFooter(hasLoadMore);
if (!isLoading && hasLoadMore) {
isLoading = true;
loadMoreListener.onLoadMore(++currPage);
}
} else {
onBindItemData(holder, items.get(position));
}
}
@Override
public int getItemCount() {
if (items == null) return 0;
return loadMoreListener == null ? items.size() : items.size() + 1;
}
@Override
public int getItemViewType(int position) {
if (loadMoreListener != null && position == getItemCount() - 1) return TYPE_FOOTER;
return TYPE_ITEM;
}
class MyFooterViewHolder extends RecyclerView.ViewHolder {
LinearLayoutCompat llLoading;
AppCompatTextView tvEnd;
public MyFooterViewHolder(@NonNull View itemView) {
super(itemView);
llLoading = itemView.findViewById(R.id.ll_loading);
tvEnd = itemView.findViewById(R.id.tv_end);
}
public void refreshFooter(boolean hasLoadMore) {
if (hasLoadMore) {
if (llLoading.getVisibility() == View.GONE) {
llLoading.setVisibility(View.VISIBLE);
}
if (tvEnd.getVisibility() == View.VISIBLE) {
tvEnd.setVisibility(View.GONE);
}
} else {
if (tvEnd.getVisibility() == View.GONE) {
tvEnd.setVisibility(View.VISIBLE);
}
if (llLoading.getVisibility() == View.VISIBLE) {
llLoading.setVisibility(View.GONE);
}
}
}
}
public interface OnLoadMoreListener {
void onLoadMore(int page);
}
}
item_loadmore.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:padding="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_end"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="没有更多了..."
android:textColor="@android:color/darker_gray" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/ll_loading"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="horizontal">
<ProgressBar
android:layout_width="30dp"
android:layout_height="30dp" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="加载中..."
android:textColor="@android:color/darker_gray" />
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.constraintlayout.widget.ConstraintLayout>
可以看到有两个抽象方法,具体的适配器新建一个类继承他,然后具体的ViewHolder和数据填充在那里面进行,比如:
public class MySearchListAdapter extends MyAdapter {
public MySearchListAdapter(List<?> items, Context context) {
super(items, context);
}
public MySearchListAdapter(List<?> items, Context context, int aPageCount) {
super(items, context, aPageCount);
}
//带有我自己view的ViewHolder返回回去
@Override
public RecyclerView.ViewHolder getItemViewHolder(ViewGroup parent, int viewType) {
return new MVViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_mv, null));
}
//具体的自己的数据绑定
@Override
public void onBindItemData(RecyclerView.ViewHolder holder, Object movieB) {
MVViewHolder mvViewHolder = (MVViewHolder) holder;
MBean mBean = (MBean) movieB;
mvViewHolder.title.setText(mBean.title);
mvViewHolder.leader.setText(mBean.leader);
mvViewHolder.actor.setText(mBean.actor);
mvViewHolder.country.setText(mBean.country);
mvViewHolder.desc_simple.setText(mBean.desc_simple);
Glide.with(context).load(mBean.imgUrl).into(mvViewHolder.iv);
mvViewHolder.itemData = mBean;
}
//MBean是你自己的modal
class MVViewHolder extends RecyclerView.ViewHolder {
TextView title, leader, actor, country, desc_simple;
ImageView iv;
ConstraintLayout cl;
MBean itemData;
public MVViewHolder(@NonNull View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title);
leader = itemView.findViewById(R.id.leader);
actor = itemView.findViewById(R.id.actor);
country = itemView.findViewById(R.id.country);
desc_simple = itemView.findViewById(R.id.desc_simple);
iv = itemView.findViewById(R.id.iv);
cl = itemView.findViewById(R.id.cl);
cl.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
}
}
}
MyFooterViewHolder是刷新的样式,你也可以自己根据产品需求自定义
分类:
Android
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端