RecyclerView的上拉自动加载
来源:互联网 发布:php 新特性 好处 编辑:程序博客网 时间:2024/05/21 02:36
最近自己做一个小项目的时候遇到了RecyclerView的上拉加载问题,之前ListView用多了,上拉加载也有很完善的库了,可是RecyclerView我在Github上搜了一搜,没发现有特别好,特别完善的库,所以我就自己网上找了一些资料。然后自己尝试去写,结果悲剧的发现,RecyclerView最关键的居然是Adapter和ViewHolder,所以我就先从这两个入手。
首先是ViewHolder,大家都知道,RecyclerView中已经有了ViewHolder类了,所以我们可以简单封装一下,就想ListView的万能ViewHolder一样封装一下:
import android.content.Context;import android.support.v7.widget.RecyclerView;import android.util.SparseArray;import android.view.View;import android.widget.TextView;public class BaseViewHolder extends RecyclerView.ViewHolder { private SparseArray<View> mViews;//集合类,layout里包含的View,以view的id作为key,value是view对象 private Context mContext;//上下文对象 public BaseViewHolder(Context context,View itemView) { super(itemView); mContext = context; mViews = new SparseArray<>(); } //通过View的id获得View public <T extends View> T getView(int viewId){ //从集合中找View,找不到再去itemView中findViewById然后添加在集合类中 View view = mViews.get(viewId); if (view == null){ view = itemView.findViewById(viewId); mViews.put(viewId,view); } return (T)view; } //通过TextView的Id找到TextView然后直接设置TextView的Text属性 public BaseViewHolder setText(int viewId,String value){ TextView textView = getView(viewId); textView.setText(value); return this; } //通过TextView的Id找到TextView然后直接设置TextView的Text属性 public BaseViewHolder setText(int viewId,int resId){ TextView textView = getView(viewId); textView.setText(resId); return this; }}对ViewHolder做了一下简单的封装,然后接下来就是重点了,写一个抽象的Adapter集成RecyclerView.Adapter,为了更好的使用,我们把这个Adapter做的全面一点,支持Header和Footer,下面就直接贴代码吧:
import android.content.Context;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;import java.util.List;public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private Context mContext; private int mLayoutId; private List<T> mDatas; private LayoutInflater mInflater; private boolean isLoading = false; private OnItemClickListener mClickListener; private OnItemLongClickListener mLongClickListener; private OnLoadMoreListener mOnLoadMoreListener; private View mHeaderViwe; private boolean HaveMoreData = true; private TextView LoadText; /** * 声明Item的状态 */ private final static int TYPE_HEADVIEW=100; private final static int TYPE_ITEM=101; private final static int TYPE_FOOTER=102; public BaseRecyclerAdapter(Context context, RecyclerView recyclerView, List<T> datas, int layoutId){ this.mLayoutId = layoutId; this.mDatas = datas; this.mContext = context; mInflater = LayoutInflater.from(context); init(recyclerView); } //获取Item总数 @Override public int getItemCount() { return mDatas.size() + 1; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { //根据viewType去判断Item的类型,创建相对应的ViewHolder if (viewType == TYPE_ITEM){ View itemView = mInflater.inflate(mLayoutId,parent,false); BaseViewHolder holder = new BaseViewHolder(mContext,itemView); return holder; }else if (viewType == TYPE_HEADVIEW){ HeaderViewHolder headViewHolder=new HeaderViewHolder(mHeaderViwe); return headViewHolder; } else{ View progressView = mInflater.inflate(R.layout.list_foot_loading,parent,false); ProgressViewHolder progressHolder = new ProgressViewHolder(progressView); return progressHolder; } } /** * 通过position判断返回的Item的类型 * @param position 索引 * @return 100返回的是头部布局,101返回的是数据源布局,102返回的是底部布局 */ @Override public int getItemViewType(int position) { //判断mHeaderView是否为空决定是否要添加头部布局 if (mHeaderViwe!=null){ if (position==getItemCount()-1){ return TYPE_FOOTER; }else if (position==0){ return TYPE_HEADVIEW; }else { return TYPE_ITEM; } }else { if (position==getItemCount()-1){ return TYPE_FOOTER; }else { return TYPE_ITEM; } } } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { if (holder instanceof BaseViewHolder){ //提醒用户复写此方法 conver(mContext,holder,mDatas.get(position)); //注册点击事件 holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mClickListener.onItemClick(v,position); } }); //注册长按事件 holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { mLongClickListener.onItemLongClick(v,position); return true; } }); } } private void init(RecyclerView recyclerView){ //为RecyclerView添加滚动监听事件 recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); //获得Item的总数 int totalItemCount = linearLayoutManager.getItemCount(); //获得最后一项的索引 int lastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition(); if (HaveMoreData && !isLoading && dy > 0 && lastVisibleItemPosition >= totalItemCount - 1){ //此时是刷新状态 if (mOnLoadMoreListener != null){ mOnLoadMoreListener.OnLoadMore(); } isLoading = true; } } }); } public void updateData(List<T> data) { mDatas.clear(); mDatas.addAll(data); notifyDataSetChanged(); } public void addAll(List<T> datas){ mDatas.addAll(datas); notifyDataSetChanged(); } /** * 加载更多ViewHolder */ public class ProgressViewHolder extends RecyclerView.ViewHolder{ public ProgressViewHolder(View itemView) { super(itemView); LoadText = (TextView) itemView.findViewById(R.id.load_text); } } /** * 头部ViewHolder */ public class HeaderViewHolder extends RecyclerView.ViewHolder{ public HeaderViewHolder(View itemView) { super(itemView); } } /** * 声明接口 */ public interface OnItemClickListener{ public void onItemClick(View view,int position); } public interface OnItemLongClickListener{ public void onItemLongClick(View view,int position); } public interface OnLoadMoreListener{ public void OnLoadMore(); } /** * 设置监听事件 */ public void setClickListener(OnItemClickListener clickListener) { mClickListener = clickListener; } public void setLongClickListener(OnItemLongClickListener longClickListener) { mLongClickListener = longClickListener; } public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) { mOnLoadMoreListener = onLoadMoreListener; } public void setLoading(boolean loading) { isLoading = loading; } public void setHaveMoreData(boolean haveMoreData) { HaveMoreData = haveMoreData; //必须判断一下LoadText是否为空,因为一进入App时刷新布局并没有创建这LoadText if (LoadText != null) { if (!haveMoreData) { LoadText.setText("没有更多了"); } else { LoadText.setText("正在加载...."); } } } public void addHeader(View headerViwe){ this.mHeaderViwe = headerViwe; } /** * 声明抽象事件 */ public abstract void conver(Context context,RecyclerView.ViewHolder holder,T t);}
这样就把RecyclerView最重要的Adapter和ViewHolder写好了。
目前这个Adapter只适用于LinearLayoutManager布局,我会继续研究一下其他布局。。
然后就是使用了,使用的话,相对就简单一点啦,因为该封装的都封装了:
Adapter.java:
import android.content.Context;import android.support.v7.widget.RecyclerView;import java.util.List;public class Adapter extends BaseRecyclerAdapter<String> { public Adapter(Context context, RecyclerView recyclerView, List<String> datas, int layoutId) { super(context, recyclerView, datas, layoutId); } @Override public void conver(Context context, RecyclerView.ViewHolder holder, String s) { //必须要判断holder是否是BaseViewHolder实例,不然会有可能导致布局混乱 if (holder instanceof BaseViewHolder){ ((BaseViewHolder) holder).setText(R.id.tv,s); } }}MainActivity.java
import android.os.Bundle;import android.support.v4.widget.SwipeRefreshLayout;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.View;import android.widget.Toast;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity { private RecyclerView mRecyclerView; private Adapter mAdapter; private List<String> mDatas = new ArrayList<>(); private int page=0; private SwipeRefreshLayout refreshLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //初始化布局 mRecyclerView = (RecyclerView) findViewById(R.id.rv); refreshLayout = (SwipeRefreshLayout) findViewById(R.id.refresh); //设置RecyclerView布局 LinearLayoutManager layout = new LinearLayoutManager(this); mRecyclerView.setLayoutManager(layout); //初始化Adapter mAdapter = new Adapter(this,mRecyclerView,mDatas,R.layout.list_item); //为RecyclerView绑定适配器 mRecyclerView.setAdapter(mAdapter); //添加上啦加载更多事件监听 mAdapter.setOnLoadMoreListener(new BaseRecyclerAdapter.OnLoadMoreListener() { @Override public void OnLoadMore() { page++; //新建一个线程去执行 new Thread(){ @Override public void run() { super.run(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } final List<String> data = new ArrayList<String>(); for (int i = 0; i < 6; i++) { data.add("page" + page + "item" + i); } //使用UI线程去执行添加数据操作 //addData()是在自定义的Adapter中自己添加的方法,用来给list添加数据 runOnUiThread(new Runnable() { @Override public void run() { if(mDatas.size() <= 30) { mAdapter.addAll(data); mAdapter.setLoading(false); } else{ mAdapter.setHaveMoreData(false); mAdapter.setLoading(false); } } }); } }.start(); } }); //添加Item的点击事件监听 mAdapter.setClickListener(new BaseRecyclerAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { Toast.makeText(MainActivity.this, "this is "+position, Toast.LENGTH_SHORT).show(); } }); //添加下拉刷新的事件监听 refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { //新建一个线程去执行 new Thread(){ @Override public void run() { super.run(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } final List<String> data = new ArrayList<String>(); for (int i = 0; i < 10; i++) { data.add("refresh item"+i); } //使用UI线程去执行数据更新操作 runOnUiThread(new Runnable() { @Override public void run() { //调用adapter中定义的更新数据的方法 mAdapter.updateData(data); refreshLayout.setRefreshing(false); //设置一下HaveMoreData的 mAdapter.setHaveMoreData(true); } }); } }.start(); } }); //初始化mData的数据 for (int i=0;i<=9;i++){ mDatas.add("item"+i); } }}
我写的这个例子是避免了重写RecyclerView,而通过Adapter去实现了上拉加载的方法,所以Adapter初始化的时候要把RecyclerView加进去,这个例子还有很多东西没有完善,但是基本的都有了,可以多多参考一下。有问题欢迎我们一起讨(tao)论(lu)一下!!
0 0
- RecyclerView的上拉自动加载
- RecyclerView的上拉加载
- RecyclerView上拉加载
- 实现 RecyclerView 上拉加载及自动加载
- android 打造真正的下拉刷新上拉加载recyclerview(四):自动加载和其他封装
- android 打造真正的下拉刷新上拉加载recyclerview(四):自动加载和其他封装
- RecyclerView的上拉加载,下拉刷新
- 简单实现上拉加载的RecyclerView
- RecyclerView 上拉加载的简单封装
- SwipeRefreshLayout+RecyclerView实现下拉刷新上拉自动加载
- SwipeRefreshLayout+RecyclerView实现下拉刷新上拉自动加载
- RecyclerView的上拉加载下拉刷新和viewpager自动有点无限轮播
- RecyclerView 上拉加载 PullToRefreshRecyclerView
- RecyclerView 上拉加载更多
- android RecyclerView上拉加载
- RecyclerView上拉加载Demo
- 自定义RecyclerView的上拉加载功能,单纯的上拉加载,适应性强
- android 打造真正的下拉刷新上拉加载recyclerview(三):下拉刷新上拉加载
- Feature Learning Based Deep Supervised Hashing with Pairwise Labels
- LabVIEW使用入门指导
- SDK manager更新失败
- 我的spark学习之路(三):利用spark做回归分析
- Spinner的简单使用
- RecyclerView的上拉自动加载
- 新浪微博授权demo
- 监听器常见应用
- FZU 2133 kk排座位
- oj计算利润
- 初识Struts2框架
- 转载:父类引用指向子类对象
- 分清setTimeout和setInterval
- 支付宝支付沙箱测试时遇到的appid无效错误