MultiTypeAdapter —— 打造高效并解耦的RecycleView适配器

MultiTypeAdapter

一款轻量级支持多数据类型的 RecyclerView 适配器; 使用简单,完全解耦;

通讯聊天界面、朋友圈布局、淘宝 UI等复杂页面 优雅快速实现,无论你是一种数据有多种VIew类型,还是多种数据多种类型,还是两者都有,统统帮你快速地、优雅地搞定!

好了,话不多说,直接开始撸代码吧 (代码为Java + Kotlin混合开发)。

1、添加依赖
implementation 'me.drakeet.multitype:multitype:3.3.0'
2、添加工具类

虽然 MultiTypeAdapter 中已经有实现方式了,但是我对其进行进一步优化封装。使用起来更加快捷简单。

首先,对ViewHolder进行封装:

ViewHolder.kt

import android.content.Context
import android.util.SparseArray
import android.view.View
import androidx.annotation.IdRes
import androidx.annotation.StringRes
import androidx.recyclerview.widget.RecyclerView

@Suppress("NOTHING_TO_INLINE")
open class ViewHolder<T>(itemView: View) : RecyclerView.ViewHolder(itemView) {
    private val cachedViews: SparseArray<View> by lazy { SparseArray<View>() }
    open var item: T? = null
    open val context: Context
        get() = itemView.context

    @Suppress("UNCHECKED_CAST")
    operator fun <T : View> get(@IdRes id: Int): T = getOptional(id)!!

    fun <T : View> getOptional(@IdRes id: Int): T? {
        val cachedView = cachedViews[id]
        return if (cachedView != null) {
            cachedView as T
        } else {
            val v = itemView.findViewById<View?>(id)
            if (v != null) {
                cachedViews.put(id, v)
            }
            v as T?
        }
    }

    fun <T : View> findViewById(@IdRes id: Int): T = get(id)

    fun getString(@StringRes id: Int, vararg args: Any?): String =
            context.getString(id, *args)


}

ViewHoder封装完成后,下一步就是封装 ItemViewBinder,

BaseLayoutBinder.kt

import android.os.Handler
import android.os.Looper
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.annotation.LayoutRes
import me.drakeet.multitype.ItemViewBinder
import java.lang.reflect.Executable
import java.util.concurrent.Executor

abstract class BaseViewHolderLayoutBinder<T, VH : ViewHolder<T>>
    : ItemViewBinder<T, VH>() {
    override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): VH {
        val holder = onCreateViewHolderImpl(inflater, parent)
        // 检查是否是执行在ui线程
        if (Looper.myLooper() == Looper.getMainLooper()) {
            onViewHolderCreated(holder)
        } else {
            Handler(Looper.getMainLooper()).post {
                Runnable() {
                    kotlin.run {
                        onViewHolderCreated(holder)
                    }
                }
            }
        }
        return holder
    }

    abstract fun onCreateViewHolderImpl(inflater: LayoutInflater, parent: ViewGroup): VH

    protected open fun onViewHolderCreated(holder: VH) {}

    override fun onBindViewHolder(holder: VH, item: T, payloads: List<Any>) {
        holder.item = item
        super.onBindViewHolder(holder, item, payloads)
    }
}

abstract class BaseLayoutBinder<T>(
        @LayoutRes private val layout: Int
) : BaseViewHolderLayoutBinder<T, ViewHolder<T>>() {

    override fun onCreateViewHolderImpl(inflater: LayoutInflater, parent: ViewGroup): ViewHolder<T> {
        return ViewHolder(inflater.inflate(layout, parent, false))
    }
}

如此,工具类就算添加完成了。两个工具类都是使用Kotlin实现的。如果不懂Kotlin的兄弟们就自己补习吧。

3、使用方法

3.1、 按照结构。首先添加一个Model类,用来保存数据, 这个没有什么好说的:

Model.java

public class Model {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

3.2、 其次,需要新建关于RecycleView的Item布局:

item_binder.xml

<?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/item"
        android:layout_width="match_parent"
        android:text="sss"
        android:textSize="20sp"
        android:gravity="center"
        android:layout_height="40dp"/>

</LinearLayout>

3.3、 然后添加Binder类,也就是Adapter类, 使Binder类继承 BaseLayoutBinder并实现onBindViewHolder:

ItemMainBinder.kt


import android.widget.TextView

abstract class ItemMainBinder : BaseLayoutBinder<Model>(R.layout.binder_item) {

    override fun onViewHolderCreated(holder: ViewHolder<Model>) {
        super.onViewHolderCreated(holder)
        holder.run {
            //添加item点击事件
            holder.itemView.setOnClickListener {
                holder.item?.let {
                    itemClick(it)
                }
            }
        }
    }
	//控制器,初始控件并绑定数据
    override fun onBindViewHolder(hoder: ViewHolder<Model>, item: Model) {
        hoder.run {
            get<TextView>(R.id.item).text = item.name

        }
    }

    abstract fun itemClick(item: Model)
}

3.4、 最后就是关于在Activity中的使用方法:


import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;

import me.drakeet.multitype.MultiTypeAdapter;

public class MainActivity extends AppCompatActivity {

    private List<Model> ms = new ArrayList<>();
    private RecyclerView recyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = this.findViewById(R.id.recyclerView);

        Model model = new Model();
        for (int i = 0; i <= 20; i++) {
            model.setName("测试" + i);
            model.setAge(i);
            ms.add(model);
        }

        // 初始化MultiTypeAdapter
        MultiTypeAdapter adapter = new MultiTypeAdapter(ms);
        //注册binder
        adapter.register(Model.class,new ItemMainBinder() {
                    @Override
                    public void itemClick(@NotNull Model item) {

                    }
                });

        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(adapter);
    }
}

以上是单一布局的实现方式,如果为单个Model且多布局实现,可利用MultiTypeAdapter的 to 方法加载多个binder。再实现 withLinker 方法,用于根据id之类区分加载某个binder。返回id值和binder初始化顺序相对应。如下方式:

 // 初始化MultiTypeAdapter
        MultiTypeAdapter adapter = new MultiTypeAdapter(models);
        //注册binder
        adapter.register(Model.class)
                .to(new ItemMainBinder() {
                    //下标为0的binder
                    @Override
                    public void itemClick(@NotNull Model item) {

                    }
                }, new MainTitleBinder() {
                    //下标为1的binder
                    @Override
                    public void onItemTitleClick(@NotNull Model item) {

                    }
                })
                .withLinker(new Linker<Model>() {
                    @Override
                    public int index(@NonNull Model model) {
                        //此处return返回的即是加载对应下标的布局
                        if (model.getAge() == 3 || model.getAge() == 10) {
                            return 1;
                        } else {
                            return 0;
                        }
                    }
                });

        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(adapter);

到此,MultiTypeAdapter的使用及封装就完结了。欢迎提出宝贵意见。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值