本文讲解TextView,ImageView等没有默认clickable属性的View单独设置onTouch事件
Android 事件传递机制:Android 事件传递机制初涉
我们知道 Button,TextView 等控件的基类都是View。只要你触摸到了任何一个控件,就一定会调用该控件的dispatchTouchEvent方法。那当我们去触摸TextView的时候,底层就会去调用TextView类(实际上是基类View)里的dispatchTouchEvent方法,所以接下来看View源码中dispatchTouchEvent()方法的具体实现。
dispatchTouchEvent()方法源码:public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true; //事件不往下传递
}
return onTouchEvent(event);
}
分析上述代码,第2行如果三个条件都为真的话,就返回true,否则执行onTouchEvent。
先看第一个条件:mOnTouchListener!=null,这个条件就是如果设置了OnTouchListener就会为true,否则是false。
第二个条件(mViewFlags & ENABLED_MASK) == ENABLED是判断当前点击的控件是否是enable的,按钮默认都是enable的,因此这个条件恒定为true。
第三个条件就比较复杂了,mOnTouchListener.onTouch(this, event),这个其实就是去回调控件注册touch事件时的onTouch方法。也就是说如果我们在onTouch方法里返回true,就会让这三个条件全部成立,从而整个方法直接返回true。如果我们在onTouch方法里返回false,就会再去执行onTouchEvent(event)方法。
TexView设置触摸事件demo
布局:<?xml version="1.0" encoding="utf-8"?>
android:layout_width="match_parent"
android:layout_height="match_parent">
android:id="@+id/activity_motionevent_textview"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_centerInParent="true"
android:gravity="center"
android:background="#FF0000"
android:textColor="#FFFFFF"
android:text="Android 自定义View之MotionEvent方法详解"/>
Java代码:public class MotionEventActivity extends AppCompatActivity {
private TextView textView;
private int lastX;
private int lastY;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_motionevent);
textView= (TextView) findViewById(R.id.activity_motionevent_textview);
textView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
int action=motionEvent.getAction();
int x= (int) motionEvent.getX();
int y= (int) motionEvent.getY();
switch(action){
case MotionEvent.ACTION_DOWN://按下
lastX=x;
lastY=y;
Log.d("TAG", "按下坐标----:("+lastX+","+lastY+")");
break;
case MotionEvent.ACTION_MOVE://移动
float offsetX=x-lastX;
float offsetY=y-lastY;
Log.d("TAG", "移动X轴位移量offsetX----:"+offsetX);
Log.d("TAG", "移动X轴位移量offsetY----:"+offsetY);
break;
case MotionEvent.ACTION_UP://抬起
Log.d("TAG", "抬起坐标----:("+x+","+y+")");
break;
}
return false;
}
});
}
}
结果:
即此时TextView按下无论如何移动TextView只打印按下动作,移动和抬起动作不执行。这是因为只设置了TextView的触摸事件OnTouchListener,而TextView默认是不可点击的,所以按照dispatchTouchEvent源码返回false执行return onTouchEvent(event);
修改布局文件<?xml version="1.0" encoding="utf-8"?>
android:layout_width="match_parent"
android:layout_height="match_parent">
android:id="@+id/activity_motionevent_textview"
android:layout_width="200dp"
android:layout_height="200dp"
android:clickable="true"
android:layout_centerInParent="true"
android:gravity="center"
android:background="#FF0000"
android:textColor="#FFFFFF"
android:text="Android 自定义View之MotionEvent方法详解"/>
即为TextView添加android:clickable="true" Java代码不变
结果:
此时 按下 移动 抬起 动作全部执行。