前言
Android提供了几种处理手势的监听器,但是监听器之间的关系比较乱,新手不太容易知道该用哪一种?什么时候该重写onTouchEvent什么时候直接实现监听器。本文对Android提供的手势监听器一一说明,并在文末给出实际项目的方案选择建议。
常见手势有:单击,长按,双击,滑动,快速滑动,缩放
处理方法有两种:重写onTouchEvent来自己识别各种手势,也可以直接使用Android提供的各种手势监听器。
Android手势监听器
GestureDetector.OnGestureListener
这个监听器能处理大部分手势,但是实际项目一般不会用它,后面说明原因
使用方法:
- Activity或者View implements GestureDetector.OnGestureListener
- 把onTouchEvent托管给GestureDetector
@Override
public boolean onTouchEvent(MotionEvent event) {
return gd.onTouchEvent(event);
}
必须重写里面的6个方法:按下,onSowPress(按下没松开),单击,拖动,长按,快速滑动。
这个监听器的缺陷:
- 必须实现该接口的所有方法,但使用者一般不关心所有的事件
- onDown(),在原生的onTouchEvent已经可以处理了,多余
- onSingleTapUp不是真正的单击:快速双击会执行两次onSingleTapUp
- onScroll()只能处理单指,不能处理多指的缩放
- 快速滑动会执行多次onScroll 在执行onFling()
- 不能处理双击事件
SimpleOnGestureListener
针对上面的缺陷,这个类可以按需实现,并且支持真正的单击onSingleTapConfirmed(双击不会执行此方法)和双击
看下源码:
public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener,
OnContextClickListener
可以看出这个类包涵了OnGestureListener所有手势,增加了双击判断。
使用方法:
public class MainActivity extends Activity{
private GestureDetector gd;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
gd = new GestureDetector(new MyGesture());
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return gd.onTouchEvent(event);
}
class MyGesture extends GestureDetector.SimpleOnGestureListener{
//按需实现自己关心的手势
@Override
public boolean onDoubleTap(MotionEvent e) {
return super.onDoubleTap(e);
}
}
}
OnDoubleTapListener
如果你只是关心点击和双击事件,那么直接实现OnDoubleTapListener 是更好的选择
ScaleGestureDetector.OnScaleGestureListener
public class MainActivity extends Activity implements ScaleGestureDetector.OnScaleGestureListener{
private ScaleGestureDetector gd;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
gd = new ScaleGestureDetector(this,this);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
gd.onTouchEvent(event);
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
Log.d("dml"," onScale detector = " + detector.getScaleFactor());
return false;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
}
}
处理缩放事件,注意onScaleBegin碧玺返回true!才能执行onScale,这个接口的缺陷:不能自己控制灵敏系数
onTouchEvent
这是在手势监听器上面的回调,所以在这里当然可以处理所有的手势。处理缩放和拖动:
public class MainActivity extends Activity{
/**
* 记录当前操作的状态,可选值为STATUS_INIT、STATUS_ZOOM_OUT、STATUS_ZOOM_IN和STATUS_MOVE
*/
private int currentStatus;
/**
* 初始化状态常量
*/
public static final int STATUS_INIT = 1;
/**
* 图片放大状态常量
*/
public static final int STATUS_ZOOM_OUT = 2;
/**
* 图片缩小状态常量
*/
public static final int STATUS_ZOOM_IN = 3;
/**
* 图片拖动状态常量
*/
public static final int STATUS_MOVE = 4;
/**
* 记录上次手指移动时的横坐标
*/
private float lastXMove = -1;
/**
* 记录上次手指移动时的纵坐标
*/
private float lastYMove = -1;
/**
* 记录上次两指之间的距离
*/
private double lastFingerDis;
/**
* 记录手指移动的距离所造成的缩放比例
*/
private float scaledRatio;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_POINTER_DOWN:
if (event.getPointerCount() == 2) {
// 当有两个手指按在屏幕上时,计算两指之间的距离
lastFingerDis = distanceBetweenFingers(event);
}
break;
case MotionEvent.ACTION_MOVE:
if (event.getPointerCount() == 1) {
// 只有单指按在屏幕上移动时,为拖动状态
float xMove = event.getX();
float yMove = event.getY();
if (lastXMove == -1 && lastYMove == -1) {
lastXMove = xMove;
lastYMove = yMove;
}
currentStatus = STATUS_MOVE;
// ------------拖动数值----------------
//after(xMove,yMove),befor(lastXMove,lastYMove)
lastXMove = xMove;
lastYMove = yMove;
} else if (event.getPointerCount() == 2) {
// 有两个手指按在屏幕上移动时,为缩放状态
double fingerDis = distanceBetweenFingers(event);
if (fingerDis > lastFingerDis) {
currentStatus = STATUS_ZOOM_OUT;
} else {
currentStatus = STATUS_ZOOM_IN;
}
// ------------缩放倍数----------------
scaledRatio = (float) (fingerDis / lastFingerDis);
}
break;
case MotionEvent.ACTION_POINTER_UP:
if (event.getPointerCount() == 2) {
// 手指离开屏幕时将临时值还原
lastXMove = -1;
lastYMove = -1;
}
break;
case MotionEvent.ACTION_UP:
// 手指离开屏幕时将临时值还原
lastXMove = -1;
lastYMove = -1;
break;
default:
break;
}
return true;
}
/**
* 计算两个手指之间的距离。
*
* @param event
* @return 两个手指之间的距离
*/
private double distanceBetweenFingers(MotionEvent event) {
float disX = Math.abs(event.getX(0) - event.getX(1));
float disY = Math.abs(event.getY(0) - event.getY(1));
return Math.sqrt(disX * disX + disY * disY);
}
}
总结
根据实际场景选择处理方式:
- 简单的单击和双击和长按:用SimpleOnGestureListener
- 简单的缩放,没有拖动:ScaleGestureDetector
- 缩放+拖动:onTouchEvent
- 多手势复杂场景:SimpleOnGestureListener + onTouchEvent
网友评论