Android无限层扩展多级recyclerview列表+实时搜索弹窗

news/2024/11/6 5:26:20 标签: android, java, 数据库, kotlin, ide

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/2767499cd5434afea18c885d0f54a1ae.png
业务逻辑:
点击选择,弹出弹窗,列表数据由后台提供,不限层级,可叠加无限层子级;
点击item展开收起,点击尾部icon单选选中,点击[确定]为最终选中,收起弹窗;
搜索框输入字符时,实时检索数据显示;
搜索出的列表点击直接选中,收起弹窗。

弹窗代码:

kotlin">class DepartListDialog {
    class Builder(context: Context) : BasicDialog.Builder<Builder>(context) {
        private val inputView: EditText? by lazy { findViewById(R.id.et_input) }
        private val titleView: TextView? by lazy { findViewById(R.id.tv_title) }
        private val leftView: TextView? by lazy { findViewById(R.id.tv_left) }
        private val rightView: TextView? by lazy { findViewById(R.id.tv_right) }
        private val clearView: ImageView? by lazy { findViewById(R.id.iv_del) }
        private val llEmpty: LinearLayout? by lazy { findViewById(R.id.ll_empty) }
        private var onLeftClick: ((BasicDialog) -> Unit)? = null
        private var onRightClick: ((String, BasicDialog) -> Unit)? = null

        private var isFilterEmail = false
        private var query = ""
        private var onItemClick: ((DepartModel, Int, BasicDialog?) -> Unit)? = null
        private var onItemSelectClick: ((View, Int, DepartModel) -> Unit)? = null
        private var onSearchItemClick: ((ArrayList<String>, DepartModel, Int, BasicDialog?) -> Unit)? = null
        private var onInputListener: ((String, BasicDialog?) -> Unit)? = null
        private val rvSearch: RecyclerView? by lazy { findViewById(R.id.rv_search) }
        private val recyclerView: RecyclerView? by lazy { findViewById(R.id.recycler_view) }
        private var recyclerAdapter: DepartTreeAdapter? = null
        private var treeItemList = arrayListOf<DepartModel>()
        private val rvSearchAdapter: CommonAdapter<DepartModel>? by lazy {
            CommonAdapter<DepartModel>(R.layout.item_string).apply {
                convert = { holder, position, item ->
                    item?.let {
                        var str = item.name
                        var cList = item.children ?: arrayListOf()
                        while (cList.isNotEmpty()) {
                            str += "/" + cList[0].name
                            cList = cList[0].children ?: arrayListOf()
                        }
                        val tvName = holder.getView<TextView>(R.id.tv_name)
                        setPartText(
                            tvName, str, query,
                            getColor(R.color.color_909090), getColor(R.color.color_303030)
                        )
                    }
                }

                setOnItemClickListener { adapter, _, position ->
                    adapter.getItem(position)?.let {
                        val ids = arrayListOf<String>()
                        var bean = it
                        ids.add(bean.id)
                        var str = bean.name
                        while (bean.children != null && bean.children?.isNotEmpty() == true) {
                            bean = bean.children!![0]
                            ids.add(bean.id)
                            str += "/" + bean.name
                        }
                        val nameArr = str.split("/")
                        if (nameArr.size > 2) {
                            bean.name =
                                "……/" + nameArr[nameArr.size - 2] + "/" + nameArr[nameArr.size - 1]
                        } else {
                            bean.name = str
                        }
                        onSearchItemClick?.invoke(ids, bean, position, getDialog())
                        dismiss()
                    }
                }
            }
        }

        init {
            setContentView(R.layout.dialog_common_input_data)
            setAnimStyle(AnimAction.ANIM_BOTTOM)
            setGravity(Gravity.BOTTOM)
            setCancelable(false)
            setCanceledOnTouchOutside(false)
            setOnClickListener(leftView, rightView, clearView)
            setRightBtnEnable(false)
            recyclerAdapter = DepartTreeAdapter(context, treeItemList)
            recyclerView?.adapter = recyclerAdapter
            recyclerAdapter?.setOnItemClickListener(object : DepartTreeAdapter.OnItemClickListener {
                override fun onItemClick(view: View, position: Int, model: DepartModel) {
//                    showToast("当前点击的数据为 ${model.name}")
                }
            })
            recyclerAdapter?.onItemChildClickListener =
                object : DepartTreeAdapter.OnItemChildClickListener {
                    override fun onClick(view: View, position: Int, model: DepartModel) {
                        onItemSelectClick?.invoke(view, position, model)
                        setRightBtnEnable(true)
                    }

                }

            rvSearch?.adapter = rvSearchAdapter
            inputView?.addTextChangedListener(object : TextWatcher {
                override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}

                override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
                }

                override fun afterTextChanged(p0: Editable?) {
                    query = inputView?.text?.trim().toString()
                    if (query.isEmpty()) {
                        rvSearchAdapter?.submitList(arrayListOf())
                        rvSearchAdapter?.notifyDataSetChanged()
                        recyclerView?.visibility = View.VISIBLE
                        val v = if ((recyclerView?.adapter?.itemCount
                                ?: 0) < 1
                        ) View.VISIBLE else View.GONE
                        llEmpty?.visibility = v
                    } else {
                        onInputListener?.invoke(query, getDialog())
                        recyclerView?.visibility = View.INVISIBLE
                    }
                    clearView?.isVisible = query.isNotEmpty()
                }
            })
        }

        fun setRightBtnEnable(enable: Boolean): Builder = apply {
            val color = if (enable) {
                if (UiUtil.isDarkMode(getContext())) getColor(R.color.color_E16C5F) else getColor(R.color.color_DD594A)
            } else {
                if (UiUtil.isDarkMode(getContext())) getColor(R.color.color_606060) else getColor(R.color.color_909090)
            }
            rightView?.setTextColor(color)
            rightView?.isEnabled = enable
        }

        fun setData(data: ArrayList<DepartModel>): Builder = apply {
            recyclerAdapter?.submitList(data)
            recyclerAdapter?.notifyDataSetChanged()
            val v = if (data.isEmpty()) View.VISIBLE else View.GONE
            llEmpty?.visibility = v
        }

        fun resetDefault() {
            recyclerAdapter?.setDefaultAdapter()
        }


        fun setSelectItem(index: Int): Builder = apply {
            recyclerAdapter?.notifyItemChanged(index)
        }

        fun setSearchData(data: ArrayList<DepartModel>): Builder = apply {
            rvSearchAdapter?.submitList(data)
            rvSearchAdapter?.notifyDataSetChanged()
            val v =
                if (data.isEmpty() && recyclerView?.visibility == View.INVISIBLE) View.VISIBLE else View.GONE
            llEmpty?.visibility = v
        }

        fun setSelectSearchItem(index: Int): Builder = apply {
            rvSearchAdapter?.notifyItemChanged(index)
        }


        fun setOnItemClick(onItemClick: ((DepartModel, Int, BasicDialog?) -> Unit)): Builder =
            apply {
                this.onItemClick = onItemClick
            }


        fun setOnItemSelectClick(onItemSelectClick: ((View, Int, DepartModel) -> Unit)): Builder =
            apply {
                this.onItemSelectClick = onItemSelectClick
            }

        fun setOnSearchItemClick(onSearchItemClick: ((ArrayList<String>, DepartModel, Int, BasicDialog?) -> Unit)): Builder =
            apply {
                this.onSearchItemClick = onSearchItemClick
            }

        fun setOnInputListener(onInputListener: ((String, BasicDialog?) -> Unit)): Builder =
            apply {
                this.onInputListener = onInputListener
            }

        override fun onClick(view: View) {
            when (view) {
                leftView -> {
                    getDialog()?.let {
                        onLeftClick?.invoke(it)
                    }
                    dismiss()
                }

                rightView -> {
                    val input = inputView?.text?.toString()?.trim() ?: ""
                    getDialog()?.let {
                        onRightClick?.invoke(input, it)
                    }
                    dismiss()
                }

                clearView -> {
                    inputView?.text?.clear()
                }
            }
        }

        // 设置标题
        fun setTitle(title: String): Builder = apply {
            titleView?.text = title
        }

        // 设置左边的文本
        fun setLeftText(leftStr: String): Builder = apply {
            leftView?.text = leftStr
        }

        // 设置右边的文本
        fun setRightText(rightStr: String): Builder = apply {
            rightView?.text = rightStr
        }

        // 设置输入类型
        fun setInputType(inputType: Int): Builder = apply {
            inputView?.inputType = inputType
        }

        // 设置输入最大长度
        fun setInputLength(maxLength: Int): Builder = apply {
            inputView?.filters = arrayOf(InputFilter.LengthFilter(maxLength))
        }

        // 设置邮箱字符过滤
        fun needFilterEmail(): Builder = apply {
            isFilterEmail = true
        }

        // 设置默认输入
        fun setDefaultInput(str: String): Builder = apply {
            inputView?.setText(str)
        }

        // 设置输入提示语
        fun setInputHint(hint: String): Builder = apply {
            inputView?.hint = hint
        }

        // 设置左边按钮点击事件
        fun setLeftClick(onLeftClick: ((BasicDialog) -> Unit)): Builder = apply {
            this.onLeftClick = onLeftClick
        }

        // 设置右边按钮点击事件
        fun setRightClick(onRightClick: ((String, BasicDialog) -> Unit)): Builder = apply {
            this.onRightClick = onRightClick
        }
    }
}

弹窗布局文件:

kotlin"><?xml version="1.0" encoding="utf-8"?>
<com.ruffian.library.widget.RRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="@dimen/dp_56"
    android:layout_gravity="bottom"
    app:background_normal="?first_bg_color"
    app:corner_radius_top_left="@dimen/dp_24"
    app:corner_radius_top_right="@dimen/dp_24"
    tools:viewBindingIgnore="true">

    <TextView
        android:id="@+id/tv_left"
        android:layout_width="wrap_content"
        android:layout_height="@dimen/dp_54"
        android:gravity="center"
        android:paddingHorizontal="@dimen/dp_17"
        android:text="@string/cancel"
        android:textColor="?third_text_color"
        android:textSize="@dimen/sp_14" />

    <TextView
        android:id="@+id/tv_right"
        android:layout_width="wrap_content"
        android:layout_height="@dimen/dp_54"
        android:layout_alignParentEnd="true"
        android:gravity="center"
        android:paddingHorizontal="@dimen/dp_17"
        android:text="@string/confirm"
        android:enabled="false"
        android:textColor="?first_btn_bg_color"
        android:textSize="@dimen/sp_14" />

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="wrap_content"
        android:layout_height="@dimen/dp_54"
        android:layout_centerHorizontal="true"
        android:gravity="center"
        android:paddingHorizontal="@dimen/dp_17"
        android:text="@string/depart_select"
        android:textColor="?first_text_color"
        android:textSize="@dimen/sp_18" />

    <View
        android:id="@+id/v_divider"
        android:layout_below="@+id/tv_title"
        android:layout_marginHorizontal="@dimen/dp_16"
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:background="?first_divider_color" />

    <com.ruffian.library.widget.RRelativeLayout
        android:id="@+id/rl_et"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_32"
        app:corner_radius="@dimen/dp_4"
        android:layout_below="@+id/v_divider"
        android:layout_margin="@dimen/dp_16"
        app:background_normal="?second_btn_bg_color">

        <ImageView
            android:id="@+id/iv_search"
            android:layout_width="@dimen/dp_16"
            android:layout_height="@dimen/dp_16"
            android:layout_centerVertical="true"
            android:contentDescription="@null"
            android:layout_marginStart="@dimen/dp_10"
            android:src="?icon_edit_search" />
        <EditText
            android:id="@+id/et_input"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginStart="@dimen/dp_10"
            android:layout_toStartOf="@+id/iv_del"
            android:layout_toEndOf="@+id/iv_search"
            android:background="@color/transparent"
            android:importantForAutofill="no"
            android:inputType="text"
            android:textColor="?first_text_color"
            android:hint="@string/please_input_depart_name"
            android:textColorHint="?first_hint_text_color"
            android:textSize="@dimen/sp_14"
            tools:ignore="LabelFor" />

        <ImageView
            android:id="@+id/iv_del"
            android:layout_width="@dimen/dp_32"
            android:layout_height="@dimen/dp_32"
            android:layout_alignParentEnd="true"
            android:contentDescription="@null"
            android:paddingHorizontal="@dimen/dp_8"
            android:paddingVertical="@dimen/dp_8"
            android:visibility="invisible"
            android:src="?icon_clear_edit" />
    </com.ruffian.library.widget.RRelativeLayout>


    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_below="@+id/rl_et"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_search"
        android:layout_below="@+id/rl_et"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?first_bg_color"/>

    <LinearLayout
        android:visibility="gone"
        android:id="@+id/ll_empty"
        android:layout_below="@+id/rl_et"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_280"
        android:background="?first_bg_color"
        android:gravity="center"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <ImageView
            android:layout_width="@dimen/dp_180"
            android:layout_height="@dimen/dp_160"
            android:src="?img_empty"/>
    </LinearLayout>

</com.ruffian.library.widget.RRelativeLayout>

树形结构的适配器:

kotlin">class DepartTreeAdapter(
    private val mContext: Context,
    private val treeItemList: ArrayList<DepartModel>
) :
    RecyclerView.Adapter<DepartTreeAdapter.KTTreeViewHolder>() {

    private var selectPosition = RecyclerView.NO_POSITION
    private var onItemClickListener: OnItemClickListener? = null
    var onItemChildClickListener: OnItemChildClickListener? = null
    private var settedAdapter = false


    fun setSelectPosition(position: Int) {
        selectPosition = position
        notifyDataSetChanged()
    }

    fun submitList(data: ArrayList<DepartModel>) {
        treeItemList.clear()
        treeItemList.addAll(data)
        notifyDataSetChanged()
    }

    fun setDefaultAdapter() {
        notifyDataSetChanged()
        settedAdapter = true
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): KTTreeViewHolder {
        val binding =
            ItemDepartmentBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return KTTreeViewHolder(binding)
    }

    override fun onBindViewHolder(holder: KTTreeViewHolder, position: Int) {
        val treeItem = treeItemList[position]
        holder.bind(treeItem)
    }

    override fun getItemCount(): Int {
        return treeItemList.size
    }

    inner class KTTreeViewHolder(val binding: ItemDepartmentBinding) :
        RecyclerView.ViewHolder(binding.root) {

        fun bind(treeItem: DepartModel) {
            // 根据层级设置左边距
            val leftPadding = (treeItem.level - 1) * 50
            binding.llIcon.setPadding(leftPadding, 0, 0, 0)
            binding.tvName.text = treeItem.name
            val icon =
                if (TestActivity.lastSelectBean?.id == treeItem.id) R.mipmap.ic_selected else R.mipmap.ic_unselect
            binding.ivSelect.setImageResource(icon)

            //设置默认已选中数据的adapter
            if (settedAdapter && TestActivity.lastSelectBean?.id == treeItem.id) {
                settedAdapter = false
                TestActivity.curAdapter = this@DepartTreeAdapter
            }

            // 根据展开状态设置箭头图标
            if (treeItem.children != null && treeItem.children?.isNotEmpty() == true) {
                if (treeItem.isOpen) {
                    binding.ivNext.rotation = 180f
                } else {
                    binding.ivNext.rotation = 0f
                }
            } else {
                binding.llIcon.visibility = View.INVISIBLE
            }

            // 设置点击事件
            itemView.setOnClickListener {
                // 切换展开状态
                treeItem.isOpen = !treeItem.isOpen
                // 局部刷新,只刷新当前点击的位置和其子项的数据
                notifyItemChanged(bindingAdapterPosition)
                onItemClickListener?.onItemClick(itemView, bindingAdapterPosition, treeItem)
//                setSelectPosition(bindingAdapterPosition)
            }

            // 如果没有数据子列表不显示
            binding.recyclerView.visibility = if (treeItem.isOpen) View.VISIBLE else View.GONE

            // 如果有子数据,设置适配器并显示箭头
            if (treeItem.children != null && treeItem.children?.isNotEmpty() == true) {
                binding.ivNext.visibility = View.VISIBLE
                binding.recyclerView.visibility = if (treeItem.isOpen) View.VISIBLE else View.GONE
                // 计算子项的级别,加上适当的偏移量
                //给了level 不用计算
//                val childLevel = treeItem.level + 1
//                treeItem.children!!.forEach { child ->
//                    child.level = childLevel
//                }
                binding.recyclerView.layoutManager = LinearLayoutManager(mContext)
                val childAdapter = DepartTreeAdapter(mContext, treeItem.children!!)
                binding.recyclerView.adapter = childAdapter
                childAdapter.setOnItemClickListener(object : OnItemClickListener {
                    override fun onItemClick(view: View, position: Int, model: DepartModel) {
                        onItemClickListener?.onItemClick(view, position, model)
                    }
                })
                childAdapter.onItemChildClickListener = object : OnItemChildClickListener {
                    override fun onClick(view: View, position: Int, model: DepartModel) {
                        TestActivity.lastSelectBean = model
                        TestActivity.curAdapter?.notifyDataSetChanged()
                        childAdapter.notifyDataSetChanged()
                        TestActivity.curAdapter = childAdapter
                        if (model.name.contains("……")) {
                            onItemChildClickListener?.onClick(view, position, model)
                        } else {
                            var name = ""
                            if (model.level > 2) {
                                name = "……/"
                            }
                            name += "${treeItem.name}/${model.name}"
                            val selModel = DepartModel(model.id, name)
                            onItemChildClickListener?.onClick(view, position, selModel)
                        }
                    }
                }
            } else {    // 没有子数据,隐藏箭头
                binding.ivNext.visibility = View.GONE
                binding.recyclerView.visibility = View.GONE
            }
            binding.ivSelect.setOnClickListener {
                TestActivity.lastSelectBean = treeItem
                TestActivity.curAdapter?.notifyDataSetChanged()
                notifyDataSetChanged()
                TestActivity.curAdapter = this@DepartTreeAdapter
                onItemChildClickListener?.onClick(it, bindingAdapterPosition, treeItem)
            }

            // 根据是否带有右箭头来设置背景颜色
//            itemView.setBackgroundColor(
//                ContextCompat.getColor(
//                    mContext,
//                    if (binding.ivNext.visibility == View.VISIBLE
//                        && bindingAdapterPosition == selectPosition
//                    ) R.color.color_public_bg else R.color.white
//                )
//            )
        }
    }

    fun setOnItemClickListener(listener: OnItemClickListener) {
        this.onItemClickListener = listener
    }

    interface OnItemClickListener {
        fun onItemClick(view: View, position: Int, model: DepartModel)
    }


    interface OnItemChildClickListener {
        fun onClick(view: View, position: Int, model: DepartModel)
    }
}

adapter绑定的item布局文件:

kotlin"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:paddingVertical="@dimen/dp_16"
        android:paddingHorizontal="@dimen/dp_16">

        <LinearLayout
            android:id="@+id/ll_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">

        <ImageView
            android:id="@+id/iv_next"
            android:layout_width="@dimen/dp_12"
            android:layout_height="@dimen/dp_12"
            android:src="?ic_expand_normal" />
        </LinearLayout>

        <TextView
            android:id="@+id/tv_name"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="@dimen/dp_6"
            android:layout_weight="1"
            android:textColor="?first_text_color"
            android:textSize="@dimen/sp_14" />

        <ImageView
            android:id="@+id/iv_select"
            android:layout_width="@dimen/dp_24"
            android:layout_height="@dimen/dp_24"
            android:src="?ic_unselect" />
    </LinearLayout>

    <View
        android:id="@+id/v_divider"
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:background="?first_divider_color"
        android:layout_marginHorizontal="@dimen/dp_16" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

实体类:

kotlin">data class DepartModel(
    var id: String = "",
    var name: String = "",
    var pid: String = "",
    var children: ArrayList<DepartModel>? = arrayListOf(),
    var level: Int = 1,
    var isOpen: Boolean = false
)

页面选中后的UI需求如下:
在这里插入图片描述

TestActivity中设置:

kotlin">    private var departData = arrayListOf<DepartModel>()
    private lateinit var builder: DepartListDialog.Builder
    private var tmpSelectDepart = DepartModel()
    private var selectDepart = DepartModel()
    //编辑页面中传入的已选择部门id
    private var department_id = ""
    //编辑页面中传入的已选择部门list(包含已选择的所有父级子级)
    private var department_list = arrayListOf<IdModel>()
    override fun initView() {
        builder = DepartListDialog.Builder(this)
        //如果是编辑页面进入,取出已选择数据选中
        if (isEditPage) {
            if (department_list.size > 0) {
                department_list.reverse()
                var departName = ""
                department_list.forEach {
                    if (department_list.indexOf(it) > 1) return@forEach
                    departName = it.name + "/" + departName
                    if (it.id.equals(department_id)) {
                        tmpSelectDepart = DepartModel(id = it.id, name = it.name)
                    }
                }
                if (department_list.size > 2) {
                    departName = "……/${departName}"
                }
                departName = departName.substring(0, departName.length - 1)
                setDepartTxt(departName)
                tmpSelectDepart.name = departName
            }
            selectDepart.id = department_id
            lastSelectBean = DepartModel(id = department_id)
        }
    }
    
    override fun observeViewModel() {
        viewModel.departList.observe(this) {
            departData = ArrayList(it)
            if (isEditPage) {//从[编辑]跳转,把选中的item展开
                if (department_list.size > 1) {
                    val ids = arrayListOf<String>()
                    department_list.forEach { selDepart -> ids.add(selDepart.id) }
                    departData.forEach { dd ->
                        if (ids.contains(dd.id)) {//find选中部门的最外层级
                            //循环把所有子级都展开
                            dd.isOpen = true
                            var cList = dd.children ?: arrayListOf()
                            var i = 0//大于10级就不读了
                            while (i++ < 10 && cList.isNotEmpty()) {
                                //子级中find选中部门的内层级
                                cList.forEach { childDd ->
                                    if (ids.contains(childDd.id)) {//find选中部门的内层级
//                                    if(childDd.id==department_id){
//                                        childDd.isSelect=true
//                                    }
                                        //子集也打开
                                        childDd.isOpen = true
                                        //接着赋值新的list循环
                                        cList = childDd.children ?: arrayListOf()
                                    }
                                }
                            }
                        }
                    }
                }
            }
            builder.setData(departData)
            if (jumpType == 2) {
                builder.resetDefault()
            }
            showDepartDialog()
        }
        viewModel.departSearchList.observe(this) {
            builder.setSearchData(ArrayList(it))
        }
	}
	
    private fun showDepartDialog() {
        if (isEditPage && lastSelectBean?.id?.isNotEmpty() == true) builder.setRightBtnEnable(true)
        builder.setOnItemSelectClick { view, pos, item ->
            tmpSelectDepart = item
        }
            .setRightClick { s, basicDialog ->
                if (tmpSelectDepart.id != selectDepart.id) {
                    //切换了部门
                    resetPos()
                }
                selectDepart = tmpSelectDepart
                setDepartTxt(selectDepart.name)
            }
            .setOnSearchItemClick { ids, departModel, pos, basicDialog ->
                if (departModel.id != selectDepart.id) {
                    //切换了部门
                    resetPos()
                }
                tmpSelectDepart = departModel
                selectDepart = departModel
                lastSelectBean = DepartModel(id = departModel.id, name = departModel.name)
                setDepartTxt(departModel.name)
                //将选中状态更新到部门列表
                builder.resetDefault()

                //从搜索中选中的,将数据open状态全部重置,使弹窗重新打开就显示出选中item
                departData.forEach { dd ->
                    if (ids.contains(dd.id)) {//find选中部门的最外层级
                        //循环把所有子级都展开
                        dd.isOpen = true
                        var cList = dd.children ?: arrayListOf()
                        var i = 0//大于10级就不读了
                        while (i++ < 10 && cList.isNotEmpty()) {
                            //子级中find选中部门的内层级
                            cList.forEach { childDd ->
                                if (ids.contains(childDd.id)) {//find选中部门的内层级
                                    //子集也打开
                                    childDd.isOpen = true
                                    //接着赋值新的list循环
                                    cList = childDd.children ?: arrayListOf()
                                } else {
                                    childDd.isOpen = false
                                }
                            }
                        }
                    } else {
                        dd.isOpen = false
                    }
                }
            }
            .setOnInputListener { s, basicDialog ->
                viewModel.searchDepartmentList("0", s)
            }
            .addOnDismissListener(object : BasicDialog.OnDismissListener {
                override fun onDismiss(dialog: BasicDialog?) {
                    setProgressShow(true)
                    builder.setSearchData(arrayListOf())
                    builder.setDefaultInput("")
                }
            })
            .setInputType(InputType.TYPE_CLASS_TEXT)
            .show()
        setProgressShow(false)
    }

    /**
     * 设置部门名称文字变色
     */
    private fun setDepartTxt(content: String) {
        val weekStr = content.substring(0, content.lastIndexOf("/") + 1)
        val weekColor =  ContextCompat.getColor(this, R.color.color_BFBFBF)
        val normalColor = ContextCompat.getColor(this, R.color.color_303030)
        setPartText(binding.tvDepart, content, weekStr, normalColor, weekColor)
    }

    companion object {
        var curAdapter: DepartTreeAdapter? = null
        var lastSelectBean: DepartModel? = null
    }

这里解释下为什么放了静态的curAdapter和lastSelectBean吧(如果不需要选中效果的话可以不要这块儿)

因为嵌套了多层子级RecyclerView和配套adapter,如果本来选中第一层,改选第二层,那么现在你去notifyAdapter的时候,只能通知到当前第二层的子Adapter,原来第一层已选中的Adapter没法通知刷新到,UI上就无法取消选择,所以直接把它放在Activity里暂存,这样Adapter更新后,Activity里的依然是上次选择时用的那一个。

lastSelectBean为什么不放在Adapter里呢,原因跟上面一样,Adapter一加载子级就是新的Adapter了,lastSelectBean也就变成新的了。

当然这种方法很der哈,但是咱就是工资也很der,这样很合理在这里插入图片描述


http://www.niftyadmin.cn/n/5740262.html

相关文章

Flink的环境搭建及使用

在idea中创建一个Maven项目&#xff0c;导入Flink的依赖&#xff0c;在代码中创建Flink环境&#xff0c;编写代码. 如果不想去找flink依赖&#xff0c;就去flink官网&#xff0c;提供了一个mvn的命令&#xff0c;快速下载在本地构建一个flink的项目&#xff0c;可以直接从这个…

【AI落地应用实战】HivisionIDPhotos AI证件照制作实践指南

最近在网上发现了一款轻量级的AI证件照制作的项目&#xff0c;名为HivisionIDPhotos。它利用AI模型实现对多种拍照场景的识别、抠图与证件照生成&#xff0c;支持轻量级抠图、多种标准证件照和排版照生成、纯离线或端云推理、美颜等功能。此外&#xff0c;项目还提供了Gradio D…

gitmakegdb

git git reset 命令 | 菜鸟教程 (runoob.com) 像嫁接一样 make Makefile | 爱编程的大丙 (subingwen.cn) # 举例: 有源文件 a.c b.c c.c head.h, 需要生成可执行程序 app ################# 例1 ################# app:a.c b.c c.cgcc a.c b.c c.c -o app################# 例…

太速科技-634-基于3U PXIe的VU3P FMC+数据接口板

基于3U PXIe的VU3P FMC数据接口板 一、产品概述 板卡是一款基于 3U PXIE 总线架构的高性能数据预处理FMC 载板&#xff0c;具有 1 个 FMC&#xff08;HPC&#xff09;接口&#xff0c;1 个 X8 GTH 背板互联接口&#xff0c;可以实现 1 路 PCIe x8。板卡主控芯片采用Xilin…

智能化运维的未来:AI和机器学习在运维中的应用

随着信息技术的不断发展,运维管理变得越来越复杂。面对海量数据、快速变化的需求和高可用性的要求,传统的运维方式已经难以满足现代企业的需求。AI和机器学习作为新一代技术,为运维管理带来了新的希望。本文将详细介绍AI和机器学习在运维中的应用,并提供相关代码示例,帮助…

分布式任务调度实现原理

目录 分布式任务调度功能 分布式任务调度实现 1.Scheduler&#xff08;调度器&#xff09; 2.Trigger&#xff08;触发器&#xff09; 3.Job&#xff08;任务&#xff09; 分布式任务调度框架 xxl-job quartz Snail Job PowerJob elastic-job 分布式任务调度功能 通…

Ubuntu /etc/sudo.conf is owned by uid 1000, should be 0 的一种解决方法

Ubuntu 命令行操作过程中&#xff0c;不小心将 /etc 整个文件夹的所属者都给了当前用户(非root)&#xff0c;导致了使用sudo 会出现以下问题&#xff0c;想将/etc所属改回来也不行了&#xff0c;进退两难 sudo: /etc/sudo.conf is owned by uid 1000, should be 0 sudo: /etc/…

无人机避障——(局部规划方法)DWA(动态窗口法)

传统的DWA算法更加倾向于车辆等差速无人车&#xff0c;旋翼无人机是全速的&#xff0c;全向的。 全局路径是通过A*算法生成的 局部路径规划效果&#xff1a; DWA算法效果&#xff1a; 过程图&#xff1a; 完整过程&#xff1a; PID算法效果&#xff1a; 过程图&#xff1a…