利用RecyclerView与BaseRecyclerViewAdapterHelper实现树形列表(多级列表)(Kotlin)

BaseRecyclerViewAdapterHelper适配器 github:https://github.com/CymChad/BaseRecyclerViewAdapterHelper
官方教程:
https://github.com/CymChad/BaseRecyclerViewAdapterHelper/wiki/Expandable-Item

先看下实现效果:
利用RecyclerView与BaseRecyclerViewAdapterHelper实现树形列表(多级列表)(Kotlin)_第1张图片

实现功能主要点在三处:
1.实体类配置
2.数据的配置
3.适配器配置

第一步:实体类配置:

1.上一级实体类需要继承AbstractExpandableItem,其中SecondTypeBean是你的下一级列表的实体类,可根据实际情况来写如自己的实体类;
2.每一级实体类都需要实现MultiItemEntity;
3.重写AbstractExpandableItem与MultiItemEntity的方法 getLevel()与getItemType() ,这两个方法的返回值都是列表的类型,每一级实体类用一个数字表示就可以。

//一级列表实体类
data class FirstTypeBean(val name: String) : AbstractExpandableItem<SecondTypeBean>(), MultiItemEntity {
    override fun getLevel(): Int {
        return 0 //代表 一级列表
    }

    override fun getItemType(): Int {
        return 0 //代表 一级列表
    }
}
//二级列表实体类
data class SecondTypeBean(val name: String) : MultiItemEntity {
    override fun getItemType(): Int {
        return 1 //代表 二级列表
    }
}

第二步:数据的配置
先把这个官方demo看明白:
addSubitem是添加下级列表 中的数据
如: lv0.addSubItem(lv1); 这里lv0是一级列表,lv1是二级列表

for (int i = 0; i < lv0Count; i++) {
            Level0Item lv0 = new Level0Item(...);
            for (int j = 0; j < lv1Count; j++) {
                Level1Item lv1 = new Level1Item(...);
                for (int k = 0; k < personCount; k++) {
                    lv1.addSubItem(new Person());
                }
                lv0.addSubItem(lv1);
            }
            res.add(lv0);
        }

然后看下demo中的数据配置代码:
这里实现了一个MyApi接口,主要是为了解决在activity中利用adapter来设置的点击事件中的position不准确,
现在是一个适配器来控制多级列表,在列表展开后position会变动,暂时我没找到解决办法,只能使用适配器中的点击事件来回掉activity中的方法

class MainActivity : AppCompatActivity(), MyApi {
    private var firstList: MutableList<FirstTypeBean>? = ArrayList() // 一级列表内容List
    private var secondtList: MutableList<SecondTypeBean>? = ArrayList() // 二级列表内容List
    private var allList: MutableList<MultiItemEntity>? = ArrayList() // 全部内容List
    private var firstBean: FirstTypeBean? = null //一级列表实体类
    private var adapter: MyExpandRecaclerAdapter? = null //树形列表适配器

    //一些模拟 数据
    private val firstString: Array<String> = arrayOf("法师", "战士", "射手", "坦克", "刺客") // 一级列表数据
    private val twoString = arrayOf(
        arrayOf("诸葛亮", "王昭君", "司马懿", "小乔", "沈梦溪"),
        arrayOf("凯", "曹操", "赵云", "花木兰", "吕布"),
        arrayOf("后羿", "公孙离", "成吉思汗", "马可波罗", "李元芳"),
        arrayOf("亚瑟", "项羽", "廉颇", "张飞", "程咬金"),
        arrayOf("韩信", "百里玄策", "李白", "孙悟空", "阿珂")
    ) // 二级列表数据 (一个二维数组)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initData() // 初始化数据
        setRecycler() // 设置RecyclerView
    }

    private fun initData() {
        for (element in firstString) { //向一级列表List添加数据
            val mfirstBean = FirstTypeBean(element)
            firstList?.add(mfirstBean)
        }
        for (a: Int in 0 until firstList!!.size) { // 依次添加一级列表数据
            firstBean = FirstTypeBean(firstList!![a].name)
            addSecond(a) // 一级列表每个数据下添加相关的 二级数据
            allList!!.add(firstBean!!) // 把整合完的数据加入全部列表中
        }
    }

    private fun addSecond(i: Int) {
        secondtList?.clear() //每次添加之前不上一次的数据清空避免重复加载
        for (element in twoString[i]) {  //向二级列表List填加数据
            val secondBean = SecondTypeBean(element)
            secondtList?.add(secondBean)
        }
        for (a: Int in 0 until secondtList!!.size) {  // 每个一级列表下的二级数据
            firstBean?.addSubItem(SecondTypeBean(secondtList!![a].name)) //添加一级列表下的二级列表数据
        }
    }

    private fun setRecycler() { // 设置RecyclerView
        recycler.layoutManager = LinearLayoutManager(this)
        adapter = MyExpandRecaclerAdapter(allList)
        adapter!!.setMyApi(this) // 实现回掉方法
        recycler.adapter = adapter
    }

    override fun first(name: String) { //接口回掉方法
        Toast.makeText(this, name, Toast.LENGTH_SHORT).show()
    }

    override fun second(name: String) { //接口回掉方法
        Toast.makeText(this, name, Toast.LENGTH_SHORT).show()
    }
}

第三步:适配器配置
这里适配器类继承BaseMultiItemQuickAdapter树形列表适配器,第一个参数是固定的MultiItemEntity
需要在初始化块中进行addItemType,添加多级列表的布局,java中就在构造方法中使用addItemType

class MyExpandRecaclerAdapter(data: MutableList<MultiItemEntity>?) :
    BaseMultiItemQuickAdapter<MultiItemEntity, BaseViewHolder>(data) {

    private val ITEM_TYPE0 = 0 // 布局类型:一级列表
    private val ITEM_TYPE1 = 1 // 布局类型:二级列表
    private var api: MyApi? = null // 回掉接口

    init {
        //有几个布局就加几个addItemType,一参事自定义的常量类型,二参是该列表的item布局
        addItemType(ITEM_TYPE0, R.layout.layout_item0)
        addItemType(ITEM_TYPE1, R.layout.layout_item1)
    }

    override fun convert(helper: BaseViewHolder?, item: MultiItemEntity?) {
        when (item?.itemType) {
            0 -> { // 类型为0是一级列表
                val firstBean: FirstTypeBean = item as FirstTypeBean
                helper!!.setText(R.id.text_item0, firstBean.name) // 设置一级列表文字
                    .setImageResource(R.id.arrow_img, if (firstBean.isExpanded) R.drawable.arrow_down else R.drawable.arrow_right) // 设置箭头图标
                helper.itemView.setOnClickListener {
                    val pos: Int = helper.adapterPosition // 获取当前项的下标
                    if (firstBean.isExpanded) { //判断当前项是否展开
                        collapse(pos) //展开就关闭
                    } else {
                        expand(pos) // 关闭就展开
                        api!!.first(firstBean.name) //点击回掉activity中的first方法来吐丝
                    }
                }

            }
            1 -> { // 类型为1是二级列表
                val secondBean: SecondTypeBean = item as SecondTypeBean // 强制类型转换
                helper!!.setText(R.id.text_item1,secondBean.name)// 设置二级列表的文本
                helper.itemView.setOnClickListener {
                    api!!.first(secondBean.name) //点击回掉activity中的first方法来吐丝
                }
            }
        }
    }

    fun setMyApi(api: MyApi) { //接收一个实现了MyApi的实例
        this.api = api
    }

}

简单的效果就实现了,以前没接触过树形列表,所以写下这篇文章记录一下,也方便自己查看,如有写的不好不对的地方,还请帮忙指出!

你可能感兴趣的:(Kotlin,加深学习)