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

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
RecyclerView布局指的是在 RecyclerView 中显示不同类型的 item,每种 item 显示的内容和布局不同。实现 RecyclerView布局,可以通过以下步骤: 1. 声明不同类型的 item 对应的布局文件。 2. 创建不同类型的 ViewHolder,继承自 RecyclerView.ViewHolder。在 ViewHolder 中找到并保存 item 中的控件。 3. 在 RecyclerView.Adapter 中实现 getItemViewType() 方法,返回当前 item 的类型。 4. 在 RecyclerView.Adapter 中实现 onCreateViewHolder() 方法,根据不同的 item 类型,创建对应的 ViewHolder。 5. 在 RecyclerView.Adapter 中实现 onBindViewHolder() 方法,根据不同的 item 类型,绑定对应的 ViewHolder。 以下是一个示例代码: ```java public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private static final int TYPE_ONE = 1; private static final int TYPE_TWO = 2; private List<MyData> mDataList; public MyAdapter(List<MyData> dataList) { mDataList = dataList; } @Override public int getItemViewType(int position) { if (mDataList.get(position).getType() == 1) { return TYPE_ONE; } else { return TYPE_TWO; } } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { LayoutInflater inflater = LayoutInflater.from(parent.getContext()); if (viewType == TYPE_ONE) { View view = inflater.inflate(R.layout.item_type_one, parent, false); return new TypeOneViewHolder(view); } else { View view = inflater.inflate(R.layout.item_type_two, parent, false); return new TypeTwoViewHolder(view); } } @Override public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) { MyData data = mDataList.get(position); if (holder instanceof TypeOneViewHolder) { ((TypeOneViewHolder) holder).mTitle.setText(data.getTitle()); } else if (holder instanceof TypeTwoViewHolder) { ((TypeTwoViewHolder) holder).mImage.setImageResource(data.getImageResId()); } } @Override public int getItemCount() { return mDataList.size(); } private static class TypeOneViewHolder extends RecyclerView.ViewHolder { TextView mTitle; TypeOneViewHolder(View itemView) { super(itemView); mTitle = itemView.findViewById(R.id.tv_title); } } private static class TypeTwoViewHolder extends RecyclerView.ViewHolder { ImageView mImage; TypeTwoViewHolder(View itemView) { super(itemView); mImage = itemView.findViewById(R.id.iv_image); } } } ``` 在这个示例中,我们定义了两种 item 类型,分别对应布局文件 `item_type_one.xml` 和 `item_type_two.xml`,并分别对应了两个 ViewHolder 类型 `TypeOneViewHolder` 和 `TypeTwoViewHolder`。在 Adapter 中,我们通过 `getItemViewType()` 方法判断当前 item 的类型,并在 `onCreateViewHolder()` 方法中根据不同的类型创建对应的 ViewHolder。在 `onBindViewHolder()` 方法中,我们根据不同的类型绑定对应的 ViewHolder。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tinyvampirepudge

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值