RecyclerView 上拉加载更多下拉刷新的一种实现

RecyclerView作为用来取代ListView的列表,其使用越来越广泛。这篇博文结合前辈文章补充说明其对上拉加载更多,下拉刷新的一种实现。

一、实现方法说明

关于下拉刷新,可以用谷歌提供的SwipeRefreshLayout来实现,而对于上拉加载更多观察RecyclerView.Adapter的onCreateViewHolder(ViewGroup parent, int viewType)中的viewType参数可添加一FootViewHolder来实现。
这种下拉刷新,上拉加载跟多的实现方式其优点是实现简单、代码较少,缺点是Adapter实现会比较复杂一点。

二、自定义Adapter实现上拉加载更多

1、这里定义一个DishAdapter,其界面布局文件item_dish如下

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="@dimen/margin_5"
    android:background="@drawable/bg_group_button"
    android:clickable="true"
    android:orientation="horizontal">

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="vertical">

        <TextView

            android:id="@+id/tv_dish_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/margin_5"
            android:maxLines="1"
            android:text="菜名"
            android:textColor="@color/decorate_blue"
            android:textSize="@dimen/text_size_14" />

        <TextView
            android:id="@+id/tv_dish_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/margin_5"
            android:maxLines="1"
            android:text="详情" />
    </LinearLayout>
</LinearLayout>

2、同时定义两个ViewHolder

class DishViewHolder extends RecyclerView.ViewHolder {
    private TextView tvName;
    private TextView tvContent;
    public DishViewHolder(View view) {
         super(view);
         tvName = (TextView) view.findViewById(R.id.tv_dish_name);
         tvContent = (TextView) view.findViewById(R.id.tv_dish_content);       
    }
}
class FootViewHolder extends RecyclerView.ViewHolder{
     private TextView tvFootMind;
     public FootViewHolder(View view){
         super(view);
         tvFootMind = (TextView)view.findViewById(R.id.tv_footer_mind);
     }
 }

3、设置几个重载方法

首先在DishAdapter中定义两个item类别常量

private static final int TYPE_ITEM = 0;//普通item view
private static final int TYPE_FOOTER=1;//底部foot view
@Override
public long getItemId(int position) {
    return super.getItemId(position);
}

@Override
public int getItemCount() {
    return mDishes.size() + 1;
}

@Override
public int getItemViewType(int position) {
    if(position + 1 == getItemCount()){
         return TYPE_FOOTER;
    }else{
         return TYPE_ITEM;
   }
}

其中mDishe是定义的DishAdapter数据集合

private List<Dish> mDishes = new ArrayList<>();

4、定义创建和绑定ViewHolder两个重载函数

onCreateViewHolder重载如下

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
     if(viewType == TYPE_ITEM){
         View itemView = LayoutInflater.from(mContext).inflate(R.layout.item_dish, parent, false);
         DishViewHolder dishViewHolder = new DishViewHolder(itemView);
         return dishViewHolder;
     }else if(viewType == TYPE_FOOTER){
         View itemView = LayoutInflater.from(mContext).inflate(R.layout.footer_recycler_load_more,parent,false);
         FootViewHolder footViewHolder = new FootViewHolder(itemView);
         return footViewHolder;
     }
     return null;
}

其中footer_recylcer_load_more为自定义的列表上拉加载更多页面布局,其实现为

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_footer_mind"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_margin="@dimen/margin_5"
        android:gravity="center"
        android:text="上拉加载更多" />

</LinearLayout>

由此可见,onCreateView方法会根据getItemViewType方法返回的列表Item类型来动态的创建对应的ViewHolder。
定义上加载更多的四个状态常量:

private int loadMoreStatus = 0;//0 提示上拉加载 1 正在上拉加载 2 无更多数据 3 隐藏上拉提示
public static final int PULL_UP_LOAD_MORE = 0;
public static final int LOADING_MORE = 1;
public static final int LOAD_END = 2;
public static final int LOAD_GONE = 3;//不可见

到这里便可以定义onBindViewHolder方法了

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
     if(holder instanceof DishViewHolder){
        ((DishViewHolder)holder).tvName.setText(mDishes.get(position).getName());
        ((DishViewHolder)holder).tvContent.setText(mDishes.get(position).getContent());
        holder.itemView.setTag(position);//没添加这句时ServerDishOnScrollListener没触发
     }else if(holder instanceof FootViewHolder){
        FootViewHolder footViewHolder = (FootViewHolder)holder;
        switch (loadMoreStatus){
            case PULL_UP_LOAD_MORE:
                footViewHolder.tvFootMind.setText("上拉加载更多...");
                break;
            case LOADING_MORE:
                footViewHolder.tvFootMind.setText("正在加载更多数据...");
                break;
            case LOAD_END:
                footViewHolder.tvFootMind.setText("已无更多数据");
                break;
            case LOAD_GONE:
                footViewHolder.tvFootMind.setVisibility(View.GONE);
                break;
            }
        }
    }

onBindViewHolder根据状态来进行不同显示。

5、分页数据加载

先定义几个控制变量

private boolean splitPage = false;//是否分页
private boolean noMoreData = false;//是否有更多数据
private boolean isRefresh = false;//是否是刷新的数据

分页变量

private int pageIndex = 1;//页面序号
private int pageSize = 10;//一次十条数据

加载数据

public void getData(JSONObject jsonObject) {
    if(!splitPage){
        mDishes.clear();
        changeMoreStatus(DishAdapter.LOAD_GONE);
    }
    if(isRefresh){
        mDishes.clear();
        isRefresh = false;
        pageIndex = 1;
        noMoreData = false;
    }
    if(jsonObject.getIntValue("code") == 0){
        JSONArray dishArray = jsonObject.getJSONArray("data");
        for (int i = 0; i < dishArray.size(); i++) {
            JSONObject json = dishArray.getJSONObject(i);
            addData(json);
        }
        if(splitPage){
            if(pageIndex == 1 && dishArray.size() < pageSize) {
                changeMoreStatus(DishAdapter.LOAD_GONE);
                noMoreData = true;
            }else if(dishArray.size() < pageSize){
                changeMoreStatus(DishAdapter.LOAD_END);
                noMoreData = true;
            }else{
                ++pageIndex;
                changeMoreStatus(DishAdapter.PULL_UP_LOAD_MORE);
            }
        }
    }else{
        HelpUtil.showToast(mContext,jsonObject.getString("message"));
    }
}

然后定义几个控制变量的get set方法,方便外部控制

public boolean getNoMoreData(){
    return noMoreData;
}

public int getPageIndex(){
    return pageIndex;
}

public int getPageSize(){
    return pageSize;
}

public void setRefresh(boolean refresh){
    isRefresh = refresh;
    pageIndex = 1;
}
public boolean isRefresh() {
    return isRefresh;
}

public void changeMoreStatus(int status){
    loadMoreStatus = status;
    notifyDataSetChanged();
}

到此为止DishAdapter关键点就基本完成。

三、上拉加载更多事件定义

这里利用RecyclerView.OnScrollListener来实现

public class ServerDishOnScrollListener extends RecyclerView.OnScrollListener {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        if (newState == RecyclerView.SCROLL_STATE_IDLE && lastVisibleItem + 1 == dishAdapter.getItemCount()) {
            if (!dishAdapter.getNoMoreData()) {
                dishAdapter.changeMoreStatus(DishAdapter.LOADING_MORE);
                getDishData();
            }
        }
    }

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
    }
}

其中getDishData为从服务器获取Dish数据方法,获取成功后直接通过dishAdapter.getData(result)即可加载更多数据,当然在使用分页时需要提前设置

this.dishAdapter.setSplitPage(true);

四、下拉刷新事件定义

我们提到了使用SwipeRefreshLayout来实现下拉刷新,那么在定义布局时候请将RecyclerView嵌入该控件中

<android.support.v4.widget.SwipeRefreshLayout
     android:id="@+id/srl_dish"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:scrollbars="vertical">

     <android.support.v7.widget.RecyclerView
         android:id="@+id/rv_server_dish"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_margin="@dimen/margin_5" />
</android.support.v4.widget.SwipeRefreshLayout>

然后使用

srlServerDish.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
    @Override
    public void onRefresh() {
        dishAdapter.setRefresh(true);
        getDishData(); //从服务器获取数据 
    }
});

同时定义刷新完成的动作

@Override
public void stopRefresh() {
    srlServerDish.setRefreshing(false);
}

当从服务器获取刷新数据后,判断时候处于刷新状态,如果是的话先停止刷新动作,然后更新数据

if(dishAdapter.isRefresh()){
    stopRefresh();
}
dishAdapter.getData(result);

那么下拉刷新的功能就算是完成了。

五、补充说明

1、DishAdatpter getData方法的定义感觉有点乱,如有更好的方法请指点;
2、给一个项目下载地址吧,请参考夏目中的ServerDishActivity页面实现,https://github.com/Yoryky/Diet.git
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值