You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中ExpandableListView的setOnChildClickListener点击事件失效求助

问题:ExpandableListView子项点击事件无法触发,组事件正常响应

我在开发中使用ExpandableListView组件时遇到问题:setOnChildClick点击事件无法正常触发,但setOnGroupExpandListener与setOnGroupClickListener事件可正常响应。以下是对应的Fragment和Adapter代码,恳请帮忙排查解决。

Fragment代码

class DiscoverFilterFragment:Fragment() {

    private lateinit var binding: FragmentFilterDiscoverBinding
    private lateinit var filterAdapter : ExpandableListAdapter
    private lateinit var titleList : List<String>
    private lateinit var itemsList : HashMap<String, List<String>>
    private val viewModel: DiscoverViewModel by activityViewModels()
    var searchText : String = ""
    var authorText : String = ""
    var dateIssueText : String = ""

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?,
    ): View {
        binding = FragmentFilterDiscoverBinding.inflate(inflater, container, false)

        getDataFromApi(searchText, authorText + ",equals", dateIssueText + ",equals")
        onItemsClickEvent()
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
    }

    private fun getDataFromApi(searchText : String, authorText : String, dateIssueText : String) {
       titleList = ArrayList()
       itemsList = HashMap()

        viewModel.discoverFilter(searchText, authorText, dateIssueText)
        viewModel.getFilterObserverableItem().observe(viewLifecycleOwner){
            it?.let { it ->
                titleList = it.keys.toList()
                itemsList = it
                filterAdapter = DiscoverFilterAdapter(requireContext(), titleList, itemsList)
                binding.expFilter.setAdapter(filterAdapter)
                (filterAdapter as DiscoverFilterAdapter).notifyDataSetChanged()
            }
        }

    }

    private fun onItemsClickEvent() {
        val expandableListView = binding.expFilter
        expandableListView.setOnGroupExpandListener {
            Toast.makeText(
                activity,
                "Open"
                ,Toast.LENGTH_SHORT).show()
        }
        expandableListView.setOnChildClickListener {
                parent, v, groupPosition, childPosition, id ->
            Toast.makeText(activity, "Clicked: ", Toast.LENGTH_SHORT).show()
            false
        }

//        expandableListView.setOnChildClickListener { parent, v, groupPosition, childPosition, id ->
//            Log.d("Items Clicked",""
//            Toast.makeText(
//                activity,
//                titleList[groupPosition]
//                        + " : "
//                        + itemsList[titleList[groupPosition]]!![childPosition],
//                Toast.LENGTH_SHORT).show()
//            false
//        }
    }
}

Adapter代码

class DiscoverFilterAdapter internal constructor(
    private val context: Context,
    private val titleList: List<String>,
    private val itemsList: HashMap<String, List<String>>) : BaseExpandableListAdapter() {

    private var authorTextLive : MutableLiveData<String> = MutableLiveData()

    fun getAuthorTextObserverable() : MutableLiveData<String> {
        return authorTextLive
    }

    override fun getGroupCount(): Int {
        return titleList.size
    }

    override fun getChildrenCount(groupPosition: Int): Int {
        return this.itemsList[this.titleList[groupPosition]]!!.size
    }

    override fun getGroup(groupPosition: Int): Any {
        return titleList[groupPosition]

    }

    override fun getChild(groupPosition: Int, childPosition: Int): Any {
        return this.itemsList[this.titleList[groupPosition]]!![childPosition]
    }

    override fun getGroupId(groupPosition: Int): Long {
        return groupPosition.toLong()
    }

    override fun getChildId(groupPosition: Int, childPosition: Int): Long {
        return childPosition.toLong()

    }

    override fun hasStableIds(): Boolean {
        return false
    }

    override fun getGroupView(
        groupPosition: Int,
        isExpanded: Boolean,
        convertView: View?,
        parent: ViewGroup?
    ): View {
        var convertView = convertView
        val listTitle = getGroup(groupPosition) as String
        if (convertView == null) {
            val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
            convertView = inflater.inflate(R.layout.discover_filter_list, null)
        }
        val titleText = convertView!!.findViewById<TextView>(R.id.listTitle)
        titleText.text = listTitle
        return convertView

    }

    override fun getChildView(
        groupPosition: Int,
        childPosition: Int,
        isLastChild: Boolean,
        convertView: View?,
        parent: ViewGroup?
    ): View {

        var convertView = convertView
        val listItems = getChild(groupPosition, childPosition) as String
        if (convertView == null) {
            val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
            convertView = inflater.inflate(R.layout.discover_filter_item, null)
        }
        val itemsText = convertView!!.findViewById<TextView>(R.id.listItem)
        itemsText.text = listItems
        return convertView
    }

    override fun isChildSelectable(groupPosition: Int, childPosition: Int): Boolean {
        return true
    }
}

排查与解决方案

1. 检查子项布局的焦点拦截

子项布局(discover_filter_item.xml)中的控件如果设置了android:focusable="true"或android:clickable="true",会抢占ExpandableListView的点击事件。需要修改子项布局里的TextView属性:

<TextView
    android:id="@+id/listItem"
    ...
    android:focusable="false"
    android:clickable="false"/>

2. 确认isChildSelectable返回值

虽然你的Adapter中已经返回true,但需确保该方法没有被其他逻辑覆盖,这个方法是子项能触发点击事件的前提条件。

3. 替代方案:在Adapter中直接设置子项点击事件

如果上述方法无效,可以在Adapter的getChildView中直接给子项设置点击监听,通过LiveData通知Fragment:

override fun getChildView(
    groupPosition: Int,
    childPosition: Int,
    isLastChild: Boolean,
    convertView: View?,
    parent: ViewGroup?
): View {
    var convertView = convertView
    val listItems = getChild(groupPosition, childPosition) as String
    if (convertView == null) {
        val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        convertView = inflater.inflate(R.layout.discover_filter_item, null)
    }
    val itemsText = convertView!!.findViewById<TextView>(R.id.listItem)
    itemsText.text = listItems
    
    // 添加子项点击监听
    itemsText.setOnClickListener {
        authorTextLive.postValue(listItems)
    }
    return convertView
}

然后在Fragment中观察LiveData处理点击:

// 在Adapter初始化后添加
filterAdapter.getAuthorTextObserverable().observe(viewLifecycleOwner) { clickedText ->
    Toast.makeText(activity, "Clicked: $clickedText", Toast.LENGTH_SHORT).show()
}

内容的提问来源于stack exchange,提问作者Nguyễn Khánh Tôn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 07:35:20