常常在为自定义组件或者View设置监听器的时候,会弹出类似于一下的警告:
Custom view view
has setOnTouchListener called on it but does not override performClick
这是由于Touch监听器的执行顺序领先于Click监听器,并且当我们在Touch中消费掉事件后(即返回为true),Click监听器的对应方法就不会执行了。简单来说是:在onTouchEvent()方法中会执行PerformClick()方法,然后在PerformClick()方法中再去执行mOnClickListener监听器。
//第一部分
public boolean onTouchEvent(MotionEvent event) {
//省略其他源码
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
if (!post(mPerformClick)) {
performClickInternal();
}
//省略其他源码
return false;
}
//第二部分
```
```
public boolean performClick() {
// We still need to call this method to handle the cases where performClick() was called
// externally, instead of through performClickInternal()
notifyAutofillManagerOnClick();
final boolean result;
final ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this);
result = true;
} else {
result = false;
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
notifyEnterOrExitForAutoFillIfNeeded(true);
return result;
}
```
```
如果我们旨在只针对Touch设置setOnTouchListener,那么系统就会警告我们,因为如果不做处理的情况下,会造成点击事件无法正常被监听到(如果有点击事件)。
常用的消除警告的方法有两种,第一种就是直接使用:
@SuppressLint("ClickableViewAccessibility")
但是这种方法依旧没有彻底解决问题,只是抑制了这种类型的警告
第二种就是针对自己设置的监听器事件本身进行设置,具体做法采用一个自定义View来举例说明
public class MyView extends View {
public MyView(Context context) {
super(context);
init(context);
}
public MyView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context){
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
@Override
public boolean performClick() {
super.performClick();
return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
return true;
case MotionEvent.ACTION_UP:
performClick();
return true;
}
return false;
}
}
只要重写performClick()和onTouchEvent()方法,使得再确定是点击事件的时候手动去执行一次performClick()就可以了。