RecyclerView的上拉自动加载

最近自己做一个小项目的时候遇到了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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值