Android中FrameLayout设置onClickListener点击无响应如何解决?
问题原因
Android的触摸事件分发优先级是子View高于父View,你的布局存在两个导致父FrameLayout收不到点击事件的原因:
- 根FrameLayout设置了
android:descendantFocusability="afterDescendants",该属性会优先将触摸事件分发给子控件处理 - 子层级多个控件都设置了
android:clickable="true",且你也给直接子LinearLayoutstatus_bar_all_contents设置了点击事件,点击事件会被子控件消费,不会向上回传给父FrameLayout
你把LinearLayout宽高改成1dp后,点击位置没有被子控件覆盖,所以能直接触发父布局的点击事件,就是这个原理。
解决方案
根据你的业务需求可选以下任意一种方案:
方案1:拦截子控件事件(无需保留子控件点击逻辑时首选)
直接修改根FrameLayout的descendantFocusability属性即可:
<!-- 把原来的afterDescendants改成blocksDescendants --> android:descendantFocusability="blocksDescendants"
该属性会让父布局直接拦截所有子控件的触摸事件,点击任何区域都会直接触发父FrameLayout的点击事件,子控件的原有点击逻辑会失效。
方案2:子控件主动触发父布局点击(需要保留子控件点击逻辑时用)
在所有子控件的点击事件末尾,主动调用父布局的点击方法即可:
以你现有的status_bar_all_contents的点击事件为例,修改代码如下:
mStatusBarAllContents.setOnClickListener(v -> { Log.d("TAG", "statusall"); // 主动触发父布局点击事件 ((View)v.getParent()).performClick(); });
如果更深层的clock_relativelayout、audio_area等可点击控件也有自定义点击逻辑,在它们的点击事件末尾也添加上述代码即可,可同时保留父子控件的点击逻辑。
方案3:关闭子控件的可点击属性
如果不需要子控件的点击逻辑,直接删除所有子控件的android:clickable="true"属性,或者在代码中设置:
mStatusBarAllContents.setClickable(false); // 其他有clickable=true的子控件也依次设置setClickable(false)
触摸事件就不会被子控件消费,会直接向上传递给父FrameLayout触发点击。
内容的提问来源于stack exchange,提问作者Huy Nguyen
相关产品推荐
相关产品推荐

