onTouch事件
做什么都好先了解原理以后的工作就会更简单,关于手势以及我们熟悉的onclick,
onLongClick事件都是基于对onTouch事件的捕捉和处理。那么在使用手势工具类的前提下我们应该去学习了解基本的onTouch事件。
onTouch常用的以下4个事件:
1、ACTION_DOWN:
表示按下了屏幕,第一个执行也是必然执行的方法。
2、ACTION_MOVE:
表示为移动手势,会不断的执行直到触摸停止。
3、ACTION_UP :
表示为离开屏幕,触摸停止的时候执行。
4、ACTION_CANCEL:
表示取消手势,不会由用户产生,而是由程序产生的。
一个Action_DOWN, 多个ACTION_MOVE, 1个ACTION_UP,就构成了Android中众多的事件。
onTouch的参数
View
受到Touch事件的view对象
MotionEvent
包含的事件的详细信息,例如触摸点的信息,触摸事件类型的信息等
MotionEvent的方法例如getRowX所描述的都是触摸点的信息。
几个重要方法的说明:
getRowX:触摸点相对于屏幕的X坐标
getRowY:触摸点相对于屏幕的Y坐标
getX: 触摸点相对于view的X坐标 :即对其进行touch监听的那个view
getY: 触摸点相对于view的X坐标
getTop: 按钮左上角相对于父view(LinerLayout)的y坐标
getLeft: 按钮左上角相对于父view(LinerLayout)的x坐标
onTouch的返回值
作用:
这里的返回值代表的是,对于这个触摸事件touch是否已经处理完成。
如果我们设置返回值为true代表的是处理完成,这样就不会再传递给下一个对象。也就是说后面的控件或者对象就不会接收到触摸事件了。
反之,后面的对象或控件会在此接收到这个触摸事件并被调用。
详细的可以看我的这篇文章:最容易理解的触摸事件传递机制
实践
在学习基础知识之后,我们来看看如何使用这些来实现一个可以拖动的view吧。
public class MoveTouch implements View.OnTouchListener {
private int[] temp = new int[2];
private int dx, dy;
private boolean isMove = false;
private Context context;
public MoveTouch(Context context) {
this.context = context;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
int x = (int) event.getRawX();
int y = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
dx = (int) event.getRawX();
dy = (int) event.getRawY();
temp[0] = x - v.getLeft();
temp[1] = y - v.getTop();
// temp[0]=(int)event.getX(); //获取触摸点view 距离该view左边的距离 等同于 x-v.getLeft() 为了 保证坐标的正确性建议使用上面的方法
// temp[1]=(int)event.getY(); //按 y - temp[1] 这样得到的不是该view距离父view的距离,而是距离屏幕顶部的距离 包括状态栏等
isMove = false;
break;
case MotionEvent.ACTION_MOVE:
/** * 对view的按下的操作进行判断是否是移动操作 */
if (Math.abs(dx - x) > 10 || Math.abs(dy - y) > 10) {
isMove = true;
}
if (isMove) {
v.layout(x - temp[0], y - temp[1], x + v.getWidth() - temp[0], y + v.getHeight() - temp[1]);
}
break;
case MotionEvent.ACTION_UP:
if (!isMove) {
Toast.makeText(context, "被点击了", Toast.LENGTH_SHORT).show();
}
break;
}
return true;//表示我自己处理这个触摸事件,不往下传递
}
}
接下来再看看触摸事件和手势
手势操作
关于手势操作,这里其实说的是Android提供的工具类,通过GestureDetector 类来识别和处理onTouch事件,简化使用。
一般用到下面的三个类。
android.view.GestureDetector
手势操作的识别类,通过他来使用下面的识别接口。
android.view.GestureDetector.SimpleOnGestureListener
手势识别的接口类,使用他可以按需重载自己想要的方法,方法多
android.view.GestureDetector.OnGestureListener;
手势识别的类,SimpleOnGestureListener接口的父类。使用他需要实现他所有的方法。
方法说明:
OnGestureListener有下面的几个方法:
按下(onDown):
在按下时调用。
抛掷(onFling):
手指在触摸屏上迅速移动,并松开的动作。
长按(onLongPress):
手指按在持续一段时间,并且没有松开。
滚动(onScroll):
手指在触摸屏上滑动。
按住(onShowPress):
手指按在触摸屏上,它的时间范围在按下起效,在长按之前。
抬起(onSingleTapUp):
手指离开触摸屏的那一刹那。
SimpleOnGestureListener比OnGestureListener多出来的方法:
双击(onDoubleTap)
双击的第二下Touch down时触发
双击事件(onDoubleTapEvent)
双击的第二下Touch down和up都会触发一次,可用e.getAction()区分。
实践
其实看到上面的介绍应该可以看出来,其实手势就是对我们的触摸事件的一些操作进行了封装,变得更简单,简洁,方便我们的使用
public class MyGesture implements View.OnTouchListener, GestureDetector.OnGestureListener {
private Context context;
private GestureDetector gestureDetector;
private int[] temp = new int[2];
private View v;
public MyGesture(Context context) {
this.context = context;
gestureDetector = new GestureDetector(context, this);
}
@Override
public boolean onDown(MotionEvent e) {
temp[0]=(int)e.getRawX()-v.getLeft();
temp[1]=(int)e.getRawY()-v.getTop();
return false;
}
/** * 用户轻触触摸屏,尚未松开或拖动,由一个1个MotionEvent ACTION_DOWN触发 // 注意和onDown()的区别,强调的是没有松开或者拖动的状态 * @param e */
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
Toast.makeText(context, "被点击了", Toast.LENGTH_SHORT).show();
return false;
}
/** * 按住然后滑动 e1 手开始触碰屏幕的位置的MotionEvent对象 * @param e1 * @param e2 手结束触碰屏幕的位置的MotionEvent对象 * @param distanceX * @param distanceY * @return */
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
int x=(int)e2.getRawX();
int y=(int)e2.getRawY();
v.layout(x-temp[0],y-temp[1],x+v.getWidth()-temp[0],y-temp[1]+v.getHeight());
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
/** * 快速滑动并且移开 * @param e1 * @param e2 * @param velocityX * @param velocityY * @return */
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
this.v=v;
gestureDetector.onTouchEvent(event);
return true;
}
}
如果使用GestureDetector.SimpleOnGestureListener代码更简洁这里我们就不是实现了,而是继承GestureDetector.SimpleOnGestureListener这个类
public class MySimpleGesture extends GestureDetector.SimpleOnGestureListener implements View.OnTouchListener{
@Override
public boolean onTouch(View v, MotionEvent event) {
return false;
}
@Override
public boolean onDown(MotionEvent e) {
return super.onDown(e);
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return super.onScroll(e1, e2, distanceX, distanceY);
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return super.onSingleTapUp(e);
}
}
实现我就不写了,有兴趣的童鞋可以做一下,练练手。~