RecyclerView多种布局排布

        事情是由工作中的一个新项目里的一个页面里的频繁改需求引起的,原来只是不同布局,上下滚动,没有类似网格排布的UI,所以我用ScrollView写的,里面包ConstraintLayout,没有问题,滚动丝滑。后面需求改了,有个地方是列表,塞一个RecyclerView进去,没问题,滚动依旧丝滑。后面,又加另一个列表,再塞一个RecyclerView进去,滚动依旧丝滑,但是,发现这个RecyclerView只显示几个item,后面的不显示了,我还各种断点查看列表数据源和Adapter是不是有问题,结果是没问题,然后给RecyclerView设置一个超大的高度,列表就显示完全了,看来还是RecyclerView嵌套在ScrollerView的问题。后面百度了一下,在RecyclerView外包一层RelativeLayout,显示就完整了,滚动也没问题。开开心心提测,后面,发现列表数据量多的时候,整个页面ANR了。

        怎么办呢?重构页面肯定是要的,普通办法是一个RecyclerView根据类型加载对应的ViewHolder,一想起来,好麻烦,心累。但是,现在可是2023年啊,有没有可能谷歌给了新的api呢?jetpack都重构了安卓框架,总该给点新花样吧?果然是有的,就是ConcatAdapter(据说是RecyclerView1.2.0开始有的,之前是另外的名字,但是功能是一样的),就是把多个Aapter整合到一块。然后就跟ArrayList一样add添加Adapter,UI就根据添加顺序显示,adapter各管各的UI和数据,耦合性大大降低。

        使用也是超级简单,RecyclerView直接setAdapter()把ConcatAdapter添加进去,然后再把不同布局的adapter添加进去,最后concatAdapter.notifyDataSetChanger()即可。

        由于我用的是Jetpack+Kotlin,mvvm是github大佬在Jetpack基础上封装的,我的写法特别简单,可能对应不上你们的代码,仅做参考。

xml布局只需传ConcatAdapter进去,设置滚动方向就好,不需要设置item布局:

<androidx.recyclerview.widget.RecyclerView
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginTop="46dp"
            android:layout_marginBottom="53dp"
            adapter="@{adapter}"
            app:layoutManager="com.kunminx.binding_recyclerview.layout_manager.WrapContentLinearLayoutManager"
            android:orientation="vertical"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"/>

如果里面的子布局仅仅是标题,列表的头部ui,这种简单layout,且不需要更新数据,它的adapter也非常简单,areItemsTheSame和areContentsTheSame都是为true,刷新列表的时候不更新,不然会闪烁一下。

class OrderListHeadAdapter @JvmOverloads constructor(
    context: Context,
    layout: Int = R.layout.adapter_orde_list_head,
    onItem:DiffUtil.ItemCallback<Int> = object : DiffUtil.ItemCallback<Int>(){
        override fun areItemsTheSame(oldItem: Int, newItem: Int) = true
        override fun areContentsTheSame(oldItem: Int, newItem: Int) = true
    }
):SimpleDataBindingAdapter<Int,AdapterOrdeListHeadBinding>(context,layout,onItem){
    override fun onBindItem(
        binding: AdapterOrdeListHeadBinding?,
        item: Int?,
        holder: RecyclerView.ViewHolder?
    ) {}
}

添加这个adapter的时候,一定要传个list,而且长度不为0,所以adapter的数据类型使用Int还是比较方便的,使用其他类型也可以。

concatAdapter.addAdapter(OrderListHeadAdapter(requireContext()).apply { submitList(mutableListOf(0)) })

列表部分也是一样,平时普通的该咋设置咋设置,再创建添加进去即可。添加完了记得刷新

concatAdapter.notifyDataSetChanged()

清空列表,只能遍历remove掉adapter,目前没找到合适的api。

比切换ViewHolder方便太多,耦合性大大降低。

       

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现 RecyclerView 多种布局,可以通过重写 getItemViewType 方法,根据不同的数据类型返回不同的布局类型,然后在 onCreateViewHolder 方法中根据 viewType 加载不同的布局文件,最后在 onBindViewHolder 方法中根据数据类型绑定数据到不同的 ViewHolder 上。 代码示例: ``` public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private List<Object> mDataList; // 枚举不同的布局类型 private static final int TYPE_ONE = 1; private static final int TYPE_TWO = 2; public MyAdapter(List<Object> dataList) { mDataList = dataList; } @Override public int getItemViewType(int position) { if (mDataList.get(position) instanceof TypeOneBean) { return TYPE_ONE; } else if (mDataList.get(position) instanceof TypeTwoBean) { return TYPE_TWO; } return super.getItemViewType(position); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case TYPE_ONE: View view1 = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_type_one, parent, false); return new TypeOneViewHolder(view1); case TYPE_TWO: View view2 = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_type_two, parent, false); return new TypeTwoViewHolder(view2); default: throw new IllegalArgumentException("invalid viewType"); } } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { Object data = mDataList.get(position); if (holder instanceof TypeOneViewHolder) { // 绑定 TypeOneViewHolder 的数据 ((TypeOneViewHolder) holder).bindData((TypeOneBean) data); } else if (holder instanceof TypeTwoViewHolder) { // 绑定 TypeTwoViewHolder 的数据 ((TypeTwoViewHolder) holder).bindData((TypeTwoBean) data); } } @Override public int getItemCount() { return mDataList.size(); } static class TypeOneViewHolder extends RecyclerView.ViewHolder { public TypeOneViewHolder(View itemView) { super(itemView); // 初始化 TypeOneViewHolder 的控件 } public void bindData(TypeOneBean data) { // 绑定 TypeOneViewHolder 的数据 } } static class TypeTwoViewHolder extends RecyclerView.ViewHolder { public TypeTwoViewHolder(View itemView) { super(itemView); // 初始化 TypeTwoViewHolder 的控件 } public void bindData(TypeTwoBean data) { // 绑定 TypeTwoViewHolder 的数据 } } } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值