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
相关产品推荐
相关产品推荐

