RecyclerView#Adapter支持无数据布局、错误布局和列表尾部的”没有更多了“布局

简介: 实际开发中,UI小姐姐都会提供通用的`无数据页面`、`错误提示页面`。针对常见的`支持下拉刷新和上拉加载更多的列表页面`,将他们的通用逻辑抽取出来,这样我们在开发过程中就只需要关注具体的业务逻辑了,无需每次通过cv来完善`无数据页面`、`错误提示页面`的逻辑了。

RecyclerView#Adapter支持无数据布局、错误布局和列表尾部的”没有更多了“布局

实际开发中,UI小姐姐都会提供通用的无数据页面错误提示页面

针对常见的支持下拉刷新和上拉加载更多的列表页面,将他们的通用逻辑抽取出来,这样我们在开发过程中就只需要关注具体的业务逻辑了,无需每次通过cv来完善无数据页面错误提示页面的逻辑了。

业务场景梳理

不支持分页

列表页根据业务场景中的是否需要分页来进行区分,不支持分页的逻辑简单。具体如下图所示:

不支持分页

不分页的列表页,请求数据后就三种结果:有数据无数据错误(当前页面无数据的前提下)

当然了 不支持分页的页面也就不需要支持上拉加载更多

支持分页

支持分页的话情况稍微复杂一点,具体业务逻辑看下图:

在这里插入图片描述

请求失败的逻辑跟不分页的场景一致。

请求成功后,需要判断是否需要清除原有数据(第一页需要清除,表示下拉刷新过);需要根据当前页码(pageNo)每页数据容量(pageSize),判断是否还有更多数据需要加载,如果没有更多数据了,则在列表底部显示没有更多布局。

实现思路

通过上面的梳理,可以看出实现的核心在于让RecyclerView.Adapter默认支持空数据页面错误数据页面没有更多布局

这个需求我们可以通过RecyclerView.Adapter.getItemCountRecyclerView.Adapter.getItemViewType来实现,通过唯一的type值来进行区分。

另外,我们还需要支持扩展,我们自己也可以添加多种类型的item,需要预留入口。

demo地址

FuncRecyclerView

如何使用

1、添加布局FuncRecyclerView

这里我们给FuncRecyclerView设置的宽高都是固定的。

<com.scwang.smart.refresh.layout.SmartRefreshLayout
    android:id="@+id/refreshLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.tinytongtong.funcrecyclerview.recyclerview.FuncRecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</com.scwang.smart.refresh.layout.SmartRefreshLayout>
2、创建数据model、viewholder和自定义的CommonFuncItem

我们自己的Item对应的数据model,需要实现FuncBaseBean接口,实现它的getViewType方法,该方法的返回值大于0,且在当前FuncRecyclerView实例中唯一即可。具体代码如下:

public class TestFuncBean implements FuncBaseBean {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int getViewType() {
        return 4;
    }
}

接着创建ViewHolder,继承CommonFuncViewHolder,具体代码如下:

static class NormalViewHolder extends CommonFuncViewHolder {
    public TextView tvName;

    public NormalViewHolder(View itemView) {
        super(itemView);
    }

    public NormalViewHolder(View itemView, FuncBaseBean funcBaseBean) {
        super(itemView, funcBaseBean);
        tvName = itemView.findViewById(R.id.tv);
    }
}

使用创建好的Model和ViewHolder,创建自定义的CommonFuncItem,代码如下:

public class TestCommonFuncItem<V extends FuncBaseBean> extends CommonFuncItem<V> {
    public TestCommonFuncItem(V v) {
        super(v);
    }

    @Override
    public CommonFuncViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list, parent, false);
        return new TestCommonFuncItem.NormalViewHolder(v, t);
    }

    @Override
    public void onBindViewHolder(final CommonFuncViewHolder vh, FuncBaseBean funcBaseBean, final int position) {
        final TestCommonFuncItem.NormalViewHolder holder = (NormalViewHolder) vh;
        TestFuncBean rib = (TestFuncBean) funcBaseBean;
        holder.tvName.setText(rib.getName());
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(holder.itemView.getContext(), String.format("点击了第%d条数据", position), Toast.LENGTH_SHORT).show();
            }
        });
    }
}

可以看出,onCreateViewHolderonBindViewHolder方法跟RecyclerView.Adapter中的使用方法一样,唯一的区别是,onBindViewHolder方法中可以拿到对应的数据FuncBaseBean,不需要我们根据position再去获取一次。

3、代码添加viewholder

接下来就是使用了,具体代码如下:

初始化添加type:

TestFuncBean testFuncBean = new TestFuncBean();
recyclerView.addCommonFuncItem(new TestCommonFuncItem(testFuncBean));
4、设置数据

网络请求成功和失败的情况:

public void onSuccess(List<FuncBaseBean> list) {
    refreshLayout.finishLoadMore();
    refreshLayout.finishRefresh();
    PageListHelper.updateSinglePageList(recyclerView, list);
}

public void onFailure(Throwable e) {
    refreshLayout.finishLoadMore();
    refreshLayout.finishRefresh();
    Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
    PageListHelper.showError(recyclerView,e);
}
/**
 * 不分页的页面,更新数据
 *
 * @param recyclerView
 * @param list
 */
public static void updateSinglePageList(FuncRecyclerView recyclerView, List<FuncBaseBean> list) {
    if (list == null || list.isEmpty()) {
        recyclerView.showEmpty();
    } else {
        recyclerView.setList(list);
    }
}

public static void showError(FuncRecyclerView recyclerView, Throwable e) {
    if (recyclerView.getListSize() == 0) {
        recyclerView.showError();
    }
}

不分页的demo请看SimplePageListActivity,支持分页的demo请看MultiPageListActivity

相关文章
|
24天前
|
UED
常见的布局方式
【10月更文挑战第22天】这些布局方式各有特点和适用场景,在实际开发中,通常会根据具体需求选择合适的布局方式或结合多种布局方式来实现理想的页面布局效果。
32 3
RecyclerView GridView模式同一行,使其高度平齐,自动适应高度最大item
RecyclerView GridView模式同一行,使其高度平齐,自动适应高度最大item
234 0
|
XML Android开发 数据格式
一个Adapter+recycleview实现多种布局,区分布局中
最近因为需要所以学习了一下recycleview,使用Adapter修饰器修饰,使用一个Adapter+recycleview实现多种布局,而不是之前的三个Adapter在同一个recycleview中实现三个布局。点击区分布局中的gridview的图片和姓名。
53 0
|
存储 缓存 索引
更好的 RecyclerView 表项子控件点击监听器
上篇介绍了一种新的监听 RecyclerView 表项点击事件的方法。实现了将点击事件和RecyclerView.Adapter解耦。这一篇介绍如何监听 RecyclerView 表项子控件点击事件。
589 0
|
Android开发
Android开发 ListView(垂直滚动列表项视图)的简单使用
Android开发 ListView(垂直滚动列表项视图)的简单使用
350 0
Android开发 ListView(垂直滚动列表项视图)的简单使用
【JetPack】视图绑定 ( ViewBinding ) 各种应用 ( 视图绑定两种方式 | Activity 布局 | 对话框布局 | 自定义组件布局 | RecyclerView 列表布局 )
【JetPack】视图绑定 ( ViewBinding ) 各种应用 ( 视图绑定两种方式 | Activity 布局 | 对话框布局 | 自定义组件布局 | RecyclerView 列表布局 )
584 0
【JetPack】视图绑定 ( ViewBinding ) 各种应用 ( 视图绑定两种方式 | Activity 布局 | 对话框布局 | 自定义组件布局 | RecyclerView 列表布局 )
tablayout支持改变选中文字大小,支持左右滑动,支持viewpager,支持三角可移动指示器
TabLayout [简书地址] (https://www.jianshu.com/p/2c3f868266e8) 基于大神的FlycoTabLayout 传送地址和基本用法 用法和属性和这个库一样 效果图如下 Gif_20180828_142709.
2491 0