父控件禁用时,如何让自定义Switch替代View忽略点击事件?
问题描述
我正在创建一个可点击的自定义View,用来替代android.widget.Switch,完全通过onDraw实现而不依赖额外的Drawable。之前用原生Switch时,只要父控件处于禁用状态,Switch也会失去点击能力;但换成这个自定义View后,父控件禁用时它依然可以点击。请问该如何判断是否应该禁用/忽略点击事件?
状态对比
- 自定义View父控件启用状态:

- 自定义View父控件禁用状态(仍可点击!):

- Switch父控件禁用状态(不可点击):

我的代码示例
public class MySwitch extends View { @Override public boolean onTouchEvent(MotionEvent motionEvent) { if (isClickable() && isEnabled()) { //do something } return super.onTouchEvent(motionEvent); } @Override protected void onDraw(Canvas canvas) { //draw track and thumb } }
解决方案
原生Switch继承自CompoundButton,这套控件体系内部已经处理了父控件禁用时的交互拦截逻辑。你的自定义View直接继承View,默认没有这个逻辑,得自己实现,下面两种方法都能解决:
方法一:在触摸事件中检查所有父控件状态
添加一个递归方法,遍历所有父控件检查是否启用,只有自身和所有父控件都处于启用状态时,才处理点击事件:
public class MySwitch extends View { // 递归检查所有父控件是否启用 private boolean areAllParentsEnabled() { ViewParent parent = getParent(); while (parent instanceof View) { if (!((View) parent).isEnabled()) { return false; } parent = parent.getParent(); } return true; } @Override public boolean onTouchEvent(MotionEvent motionEvent) { // 同时满足自身可点击、自身启用、所有父控件启用,才处理逻辑 if (isClickable() && isEnabled() && areAllParentsEnabled()) { // 处理你的点击/切换逻辑 return true; } // 不满足条件时,交给View默认逻辑处理 return super.onTouchEvent(motionEvent); } @Override protected void onDraw(Canvas canvas) { // draw track and thumb } }
方法二:重写isEnabled()关联父控件状态
通过重写isEnabled()方法,让自定义View的启用状态自动包含父控件的状态检查,这样原来的触摸事件判断逻辑不用修改:
public class MySwitch extends View { @Override public boolean isEnabled() { // 先检查自身是否启用 boolean selfEnabled = super.isEnabled(); if (!selfEnabled) { return false; } // 再遍历所有父控件检查状态 ViewParent parent = getParent(); while (parent instanceof View) { if (!((View) parent).isEnabled()) { return false; } parent = parent.getParent(); } return true; } @Override public boolean onTouchEvent(MotionEvent motionEvent) { // 原来的判断逻辑不变,因为isEnabled()已经包含了父控件状态 if (isClickable() && isEnabled()) { // 处理你的点击/切换逻辑 return true; } return super.onTouchEvent(motionEvent); } @Override protected void onDraw(Canvas canvas) { // draw track and thumb } }
补充说明
Android原生控件的交互逻辑中,当父控件禁用时,子控件的触摸事件会被拦截或者默认不响应。而直接继承View的自定义控件没有这个默认处理,所以需要手动添加父控件状态的检查逻辑,确保和原生控件的行为一致。
内容的提问来源于stack exchange,提问作者Ayaka_Ago
相关产品推荐
相关产品推荐

