一.事件类型
这里就引入关于 MotionEvent 的一个重要概念,事件类型。事件类型就是指对象所代表的动作。比如说,当你的一个手指在屏幕上滑动一下时,系统会产生一系列的触摸事件对象,他们所代表的动作有所不同。有的事件代表你手指按下这个动作,有的事件代表你手指在屏幕上滑动,还有的事件代表你手指离开屏幕。常用的如下几种:
ACTION_DOWN:手指按下
ACTION_MOVE:手指一动
ACTION_UP:手指抬起
ACTION_CANCEL:事件取消(极少用到)
二.事件序列
正常情况下,手指触摸屏幕的行为,会触发一系列点击事件,常见的如下几种:
点击屏幕后离开松开,事件序列为 DOWN → UP
点击屏幕滑动一会再松开,事件序列为 DOWN → MOVE → ... → MOVE → UP
三.MotionEvent getX() getY() Demo
布局
<strong><?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
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方法详解"/>
</RelativeLayout></strong>
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;
}
});
}
}
图解
效果
通过MotionEvent对象我们可以得到点击事件发生的x和y坐标。
系统为我们提供了getX() / getY()和getRawX() / getRawY()。
getX() getY()返回的是相对于相对当前View的左上角的x和y坐标。
getRawX() getRawY()返回的是相对于手机屏幕左上角的x和y坐标。
四.MotionEvent getRawX() getRawY() Demo
布局
<strong><?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
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方法详解"/>
</RelativeLayout></strong>
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.getRawX();
int y= (int) motionEvent.getRawY();
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;
}
});
}
}
效果
五.滑动的最小距离TouchSlop
TouchSlop是系统所能识别出的被认为是滑动的最小距离。这是一个常量,就是说,当你手指在屏幕滑动大于这个常量,系统才会认定你滑动屏幕了,它和设备有关,不同的设备这个值可能是不同的。
我们可以通过如下代码获取这个常量:ViewConfiguration.get(this).getScaledTouchSlop();
代码
float TouchSlop= ViewConfiguration.get(MotionEventActivity.this).getScaledTouchSlop();
Log.d("TAG", "TouchSlop----:"+TouchSlop);
效果
即当前设备下滑动的最小距离是24
六.总结
关于OnTouchEvent(MotionEvent事件)事件的层级传递。我们都知道如果给一个控件注册了touch事件,每次点击它的时候都会触发一系列的ACTION_DOWN,ACTION_MOVE,ACTION_UP等事件。这里需要注意,如果你在执行ACTION_DOWN的时候返回了false,后面一系列其它的action就不会再得到执行了。简单的说,就是当dispatchTouchEvent在进行事件分发的时候,只有前一个action返回true,才会触发后一个action。