美文网首页Android技术知识
RecyclerView多类型Item的正确实现姿势

RecyclerView多类型Item的正确实现姿势

作者: Android进阶架构 | 来源:发表于2020-12-05 21:51 被阅读0次

    作者:onlyloveyd
    转载:https://blog.csdn.net/poorkick/article/details/54345302

    简介

    RecyclerView是我们开发过程中经常使用到的一个元素,原生的RecyclerView.Adapter基本上可以满足一般的需求,关于RecyclerView的基础介绍请移步:

    RecyclerView基础使用

    关于多类型的Item,原生的Adapter可以通过getItemViewType返回对应的ViewHolder类型,然后在onCreateViewHolder传入的type参数,生成不同的ViewHolder,更要命的是数据绑定过程中onBindViewHolder只传入ViewHolder对象和position,针对不同的ViewHolder,我们只能通过instanceof和强制类型装换来对不同的ViewHolder进行不同的数据操作。

    这样做的弊端就是,后续如果需要添加一个类型,几乎需要修改Adapter类中的每一个方法,不利于维护。

    类结构

    目的

    1. 便于维护。增删Item的类型不需要修改Adapter的代码;
    2. 条例清晰。不同类型的Item对应不同的Bean类,对应不用的ViewHolder,对应不同的layout
      item type <----> layout <—> ViewHolder <----> java bean
    3. 工厂接口。抽象出TypeFactory接口,针对同一个Bean,可以使用不同的layout和不同的ViewHolder。

    思路

    1. 所有Bean类实现统一Visitable接口,实现type方法,返回对应的layout id;
    2. 创建BaseViewHolder使用泛型,T为Bean类。使用SparseArray存储View,View的id作为唯一标识。
    3. 具体的ViewHolder类,继承BaseViewHolder,传入不同的Bean类,方便不同的ViewHolder中绑定不同的数据。
    4. Adapter实现中使用Visitable List同一处理列表数据,使用事项TypeFactory接口的实例返回ItemType,viewHolder等

    代码结构

    代码内容

    Visitable接口

    public interface Visitable {
        int type(TypeFactory typeFactory);
    }
    

    TypeFactory接口

    public interface TypeFactory {
        int type(BannerBean bannerBean);
        int type(ContentBean contentBean);
        int type(SearchBean searchBean);
        int type(DividerBean dividerBean);
        BaseViewHolder createViewHolder(int type, View itemView);
    }
    

    BaseViewHolder抽象类

    public abstract  class BaseViewHolder<T> extends RecyclerView.ViewHolder{
        SparseArray<View> mViews;
        View mItemView;
    
        public BaseViewHolder(View itemView) {
            super(itemView);
            mItemView = itemView;
            mViews = new SparseArray<>();
        }
    
        public View getView(int resId) {
            View view = mViews.get(resId);
    
            if(view== null) {
                view = mItemView.findViewById(resId);
                mViews.put(resId, view);
            }
            return view;
        }
    
        public abstract void bindViewData(T data);
    }
    

    TypeFactory实现类~ItemTypeFactory

    public class ItemTypeFactory implements TypeFactory {
        public static final int BANNER_ITEM_LAYOUT = R.layout.rv_item_banner;
        public static final int CONTENT_ITEM_LAYOUT = R.layout.rv_item_content;
        public static final int SEARCH_ITEM_LAYOUT = R.layout.rv_item_search;
        public static final int DIVIDER_ITEM_LAYOUT = R.layout.rv_item_divider;
    
        @Override
        public int type(BannerBean bannerBean) {
            return BANNER_ITEM_LAYOUT;
        }
    
        @Override
        public int type(ContentBean contentBean) {
            return CONTENT_ITEM_LAYOUT;
        }
    
        @Override
        public int type(DividerBean dividerBean){
            return DIVIDER_ITEM_LAYOUT;
        }
    
        @Override
        public int type(SearchBean dividerBean){
            return SEARCH_ITEM_LAYOUT;
        }
    
        @Override
        public BaseViewHolder createViewHolder(int type, View itemView) {
            switch (type) {
                case BANNER_ITEM_LAYOUT:
                    return new BannerViewHolder(itemView);
                case SEARCH_ITEM_LAYOUT:
                    return new SearchViewHolder(itemView);
                case CONTENT_ITEM_LAYOUT:
                    return new ContentViewHolder(itemView);
                case DIVIDER_ITEM_LAYOUT:
                    return new DividerViewHolder(itemView);
                default:
                    return null;
            }
        }
    }
    

    各种Java Bean类

    BannerBean

    public class BannerBean implements Visitable {
        int[] mResIds;
    
        public BannerBean(int[] mResIds) {
            this.mResIds = mResIds;
        }
    
        public int[] getmResIds() {
            return mResIds;
        }
    
        public void setmResIds(int[] mResIds) {
            this.mResIds = mResIds;
        }
    
        @Override
        public int type(TypeFactory typeFactory) {
            return typeFactory.type(this);
        }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="200dp">
    
        <cn.bingoogolapple.bgabanner.BGABanner
            android:id="@+id/bgabanner_header"
            android:layout_width="match_parent"
            android:layout_height="200dp">
        </cn.bingoogolapple.bgabanner.BGABanner>
    
    </LinearLayout>
    

    ContentBean

    public class ContentBean implements Visitable{
        String content;
    
        public String getContent() {
            return content;
        }
    
        public void setContent(String content) {
            this.content = content;
        }
    
        public ContentBean(String content) {
    
            this.content = content;
        }
    
        @Override
        public int type(TypeFactory typeFactory) {
            return typeFactory.type(this);
        }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/tv_content"
            android:textStyle="italic"
            android:fontFamily="sans-serif-condensed"
            android:textSize="16sp"
            android:gravity="center_horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
    

    DividerBean

    public class DividerBean implements Visitable{
    
        @Override
        public int type(TypeFactory typeFactory) {
            return typeFactory.type(this);
        }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/divider">
    
    </LinearLayout>
    

    SearchBean

    public class SearchBean implements Visitable {
        @Override
        public int type(TypeFactory typeFactory) {
            return typeFactory.type(this);
        }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal" android:layout_width="match_parent"
        android:layout_height="50dp"
        android:padding="6dp">
    
        <EditText
            android:layout_marginLeft="30dp"
            android:id="@+id/et_search"
            android:layout_width="0dp"
            android:layout_weight="9"
            android:maxLines="1"
            android:textSize="10sp"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:hint="输入文字搜索..."
            android:background="@drawable/bg_search"
            android:layout_height="match_parent" />
    
        <ImageView
            android:id="@+id/bt_search"
            android:layout_width="0dp"
            android:layout_weight="2"
            android:src="@drawable/search"
            android:layout_height="match_parent" />
    </LinearLayout>
    

    MultiRecyclerAdapter

    public class MultiRecyclerAdapter extends RecyclerView.Adapter<BaseViewHolder> {
        List<Visitable> mData;
        TypeFactory typeFactory;
    
        public MultiRecyclerAdapter(List<Visitable> mData) {
            this.mData = mData;
            this.typeFactory = new ItemTypeFactory();
        }
    
        @Override
        public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
            return typeFactory.createViewHolder(viewType, view);
        }
    
        @Override
        public void onBindViewHolder(BaseViewHolder holder, int position) {
            holder.bindViewData(mData.get(position));
        }
    
        @Override
        public int getItemViewType(int position) {
            return mData.get(position).type(typeFactory);
        }
    
        @Override
        public int getItemCount() {
            return (mData != null ? mData.size() : 0);
        }
    }
    

    示例

    public class MultiActivity extends AppCompatActivity {
    
        @BindView(R.id.rv_content)
        RecyclerView rvContent;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_weather);
            ButterKnife.bind(this);
    
            List<Visitable> beans = new ArrayList<>();
            int[] resIds = {R.mipmap.banner_one, R.mipmap.banner_two, R.mipmap.banner_three, R.mipmap.banner_four, R.mipmap.banner_five};
            beans.add(new BannerBean(resIds));
            beans.add(new SearchBean());
            beans.add(new DividerBean());
            beans.add(new ContentBean("one"));
            beans.add(new ContentBean("one"));
            beans.add(new ContentBean("one"));
            beans.add(new DividerBean());
            beans.add(new ContentBean("two"));
            beans.add(new ContentBean("two"));
            beans.add(new ContentBean("two"));
            beans.add(new DividerBean());
            beans.add(new ContentBean("three"));
            beans.add(new ContentBean("three"));
            beans.add(new ContentBean("three"));
            beans.add(new DividerBean());
            beans.add(new ContentBean("four"));
            beans.add(new ContentBean("four"));
            beans.add(new ContentBean("four"));
            beans.add(new DividerBean());
    
            MultiRecyclerAdapter multiRecyclerAdapter = new MultiRecyclerAdapter(beans);
            LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
    
            rvContent.setAdapter(multiRecyclerAdapter);
            rvContent.setLayoutManager(linearLayoutManager);
    
        }
    }
    

    简单效果

    喜欢本文的话,不妨顺手给我点个小赞、评论区留言或者转发支持一下呗😜😜😜~
    点击【GitHub】还有彩蛋哦!!!

    Android 知识点汇总

    相关文章

      网友评论

        本文标题:RecyclerView多类型Item的正确实现姿势

        本文链接:https://www.haomeiwen.com/subject/gnknwktx.html