为ViewGroup设置点击监听器,如何识别被点击的子View
解决方案
别用普通的setOnClickListener,给FrameLayout设置OnTouchListener,在触摸抬起阶段通过ViewGroup原生方法找到实际被点击的子View即可,完全是非hack的官方实现方式:
1. 调整监听器接口(可选,语义更清晰)
interface Listener { fun onChildViewClicked(childView: View?) }
2. 父类中设置触摸监听
frameLayoutParentView.setOnTouchListener { v, event -> if (event.action == MotionEvent.ACTION_UP) { // 获取触摸点在父容器内的坐标 val touchX = event.x val touchY = event.y // 找到该坐标下的最顶层子View val clickedChild = (v as ViewGroup).findChildViewUnder(touchX, touchY) // 回调给监听器,拿到子View的ID做业务逻辑 clickListener?.onChildViewClicked(clickedChild) } // 返回false,不拦截子View自身的点击事件(如果需要拦截子View事件就返回true) false }
补充说明
findChildViewUnder是ViewGroup自带的方法,专门用来根据坐标查找对应的子View,完全符合需求,不存在任何hack手段。- 选择
ACTION_UP事件是因为点击操作的完整流程是按下再抬起,这个时机判断更贴合用户的点击行为逻辑。 - 如果只需要在点击到子View时才触发逻辑,可以加个非空判断:
if (clickedChild != null) { clickListener?.onChildViewClicked(clickedChild) }
内容的提问来源于stack exchange,提问作者MaaAn13
相关产品推荐
相关产品推荐

