- GestureDetector & OnTouchListener 区别
OnTouchListener 实现了如触摸屏相关的事件
OnGestureListener实现了 手势相关的事件
首先看OnTouchListener
Class 结构:
我们可以看出里面的概要方法有一个onTouch 方法这个方法就是我们需要实现的一个方法,
Called when a touch event is dispatched to a view.
一个触摸事件调用时被分配到一个视图中。从而实现对触摸时间的监听
例子:
public class Main3 extends Activity implements View.OnTouchListener{
private ImageView image;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
image = (ImageView) findViewById(R.id.image);
//监听这个ImageView组件上的触摸屏时间
image.setOnTouchListener(this);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_UP:
Log.e("ACTION_UP","Touch" +event.getAction());
break;
case MotionEvent.ACTION_DOWN:
Log.e("ACTION_DOWN","Touch" +event.getAction());
break;
case MotionEvent.ACTION_MOVE:
Log.e("ACTION_MOVE","Touch" +event.getAction());
break;
}
return true;
}
}
我们可以通过MotionEvent的getAction()方法来获取Touch事件的类型,包括 ACTION_DOWN(按下触摸屏), ACTION_MOVE(按下触摸屏后移动受力点), ACTION_UP(松开触摸屏)和ACTION_CANCEL(不会由用户直接触发)。借助对于用户不同操作的判断,结合getRawX()、 getRawY()、getX()和getY()等方法来获取坐标后,我们可以实现诸如拖动某一个按钮,拖动滚动条等功能。
可以看到OnTouchListener只能监听到三种触摸事件,即按下,移动,松开,如果想要监听到双击、滑动、长按等复杂的手势操作,这个时候就必须得用到OnGestureListener了。
接下来是OnGestureListener
结构图:
OnGestureListener 里面的方法
onDown // 用户轻触触摸屏
OnFling // 用户快速抛掷
OnLongPress // 用户长按触摸屏
OnScroll // 用户按下触摸屏,并拖动
OnShowPrees // 用户轻触触摸屏,尚未松开或拖动
OnSingleTapup // 用户(轻触触摸屏后)松开
这里有疑问了,我们ontouch 是通过设置他的监听事件来运行的,可是Gesture 里面并没有找到这个设置事件呢?还是可以在文档中找到的
文档中说是需要在Ontouch的监听 里面 调用 他的 onTouchEvent 事件这样就可以监听手势了
例子:
public class Main3 extends Activity implements View.OnTouchListener, GestureDetector.OnGestureListener {
private ImageView image;
private GestureDetector mGestureDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
image = (ImageView) findViewById(R.id.image);
//监听这个ImageView组件上的触摸屏时间
image.setOnTouchListener(this);
// mGestureDetector = new GestureDetector(this);
//
// GestureDetector的构造函数在4.1版本中已经过时,可以使用推荐的:
// 注意前一个this代表的是一个Context,后一个this代表的是一个OnGestureListener。
// Activity继承自Context, 而你的activity应该实现了(implements)OnGestureListener接口。
mGestureDetector = new GestureDetector(this, this);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
// switch (event.getAction()){
// case MotionEvent.ACTION_UP:
// Log.e("ACTION_UP","Touch" +event.getAction());
// break;
// case MotionEvent.ACTION_DOWN:
// Log.e("ACTION_DOWN","Touch" +event.getAction());
// break;
// case MotionEvent.ACTION_MOVE:
// Log.e("ACTION_MOVE","Touch" +event.getAction());
// break;
//
// }
//
// return true;
return mGestureDetector.onTouchEvent(event);
}
// 用户轻触触摸屏
@Override
public boolean onDown(MotionEvent e) {
Log.e("MyGesture", "onDown");
return true;
}
// 用户轻触触摸屏,尚未松开或拖动
@Override
public void onShowPress(MotionEvent e) {
Log.e("MyGesture", "onShowPress");
}
// 用户(轻触触摸屏后)松开,
@Override
public boolean onSingleTapUp(MotionEvent e) {
Log.e("MyGesture", "onSingleTapUp");
return true;
}
// 用户按下触摸屏,并拖动
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
Log.e("MyGesture", "onScroll");
return true;
}
// 用户长按触摸屏
@Override
public void onLongPress(MotionEvent e) {
Log.e("MyGesture", "onLongPress");
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
Log.e("MyGesture", "onFling");
return true;
}
}
下面是几个方法的调用顺序:
长按
10-16 16:05:45.319 10496-10496/? E/MyGesture﹕ onDown
10-16 16:05:45.489 10496-10496/? E/MyGesture﹕ onShowPress
10-16 16:05:45.999 10496-10496/? E/MyGesture﹕ onLongPress
轻触
10-16 16:06:10.479 10496-10496/? E/MyGesture﹕ onDown
10-16 16:06:10.549 10496-10496/? E/MyGesture﹕ onSingleTapUp
拖动
10-16 16:06:35.709 10496-10496/? E/MyGesture﹕ onDown
10-16 16:06:36.469 10496-10496/? E/MyGesture﹕ onScroll
10-16 16:06:36.489 10496-10496/? E/MyGesture﹕ onScroll
10-16 16:06:36.499 10496-10496/? E/MyGesture﹕ onScroll
抛掷
10-16 16:07:15.249 10496-10496/? E/MyGesture﹕ onDown
10-16 16:07:15.359 10496-10496/? E/MyGesture﹕ onScroll
10-16 16:07:15.379 10496-10496/? E/MyGesture﹕ onScroll
10-16 16:07:15.389 10496-10496/? E/MyGesture﹕ onScroll
10-16 16:07:15.409 10496-10496/? E/MyGesture﹕ onScroll
10-16 16:07:15.419 10496-10496/? E/MyGesture﹕ onFling
(1)MotionEvent中 e1是手指第一次按上屏幕的起点,e2是抬起手指离开屏幕的终点,根据上图Android屏幕坐标系可知:
手指向右滑动,终点(e2)在起点(e1)的右侧,有e2.getX() - e1.getX() 大于0 手指向左滑动,终点(e2)在起点(e1)的左侧,有e2.getX() - e1.getX() 小于0 手指向下滑动,终点(e2)在起点(e1)的下侧,有e2.getY() - e1.getY() 大于0 手指向上滑动,终点(e2)在起点(e1)的上侧,有e2.getY() - e1.getY() 小于0
(2)onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
distanceX,是前后两次call的X距离,不是e2与e1的水平距离 distanceX,是前后两次call的Y距离,不是e2与e1的垂直距离 具体数值的方向,请详见上图(中)
(3)onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
velocityX,是X轴的每秒速度 velocityY,是Y轴的每秒速度 具体数值的方向,请详见上图(右) 仔细观察可以发现:velocityX、velocityY的方向与distanceX、distanceY方向正好相反
- GestureDetector 内容方法
下面是GestureDetector 的具体使用方法,使用抛掷做的一个切换界面的demo,判断了四个方向的手势。
public class MainActivity extends Activity implements View.OnTouchListener, GestureDetector.OnGestureListener {
//创建一个用于识别手势 的GestureDetecttor 对象
private GestureDetector detector = new GestureDetector(this);
//定义一个数组,用于放漂亮的女孩
int[] girls = new int[]{R.drawable.girl1, R.drawable.girl2, R.drawable.girl3};
//定义数组下标,以方便观看各个女孩
private int index;
private ImageView image;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
image = (ImageView) findViewById(R.id.image);
//设置一个初始显示的girl吧
image.setImageResource(girls[index]);
//监听这个ImageView组件上的触摸屏时间
image.setOnTouchListener(this);
//下面两个要记得设哦,不然就没法处理轻触以外的事件了,例如抛掷动作。
image.setLongClickable(true);
detector.setIsLongpressEnabled(true);
}
//用于呼喊下一个女孩的方法
public void goNext() {
index++;
index = Math.abs(index % girls.length);
image.setImageResource(girls[index]);
}
//用户呼唤上一个女孩的方法
public void goPrevious() {
index--;
index = Math.abs(index % girls.length);
image.setImageResource(girls[index]);
}
//此方法在触摸屏被触摸,即发生触摸事件(接触和抚摸两个事件,挺形象)的时候被调用。
@Override
public boolean onTouch(View v, MotionEvent event) {
detector.onTouchEvent(event);
return true;
}
//在抬起时被调用
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
//在按住时被调用
@Override
public void onShowPress(MotionEvent e) {
}
//在滚动时调用
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
//在长按时被调用
@Override
public void onLongPress(MotionEvent e) {
}
// 在抛掷动作时被调用
// @Override
// public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
//
// //velocityX表示横向的移动,根据手指移动的方向切换女孩
// Log.e("x",velocityX+"");
// Log.e("y",velocityY+"");
//
// if (velocityX < 300) {
// goNext();
// } else if (velocityX > 300) {
// goPrevious();
// }
// return false;
// }
private DisplayMetrics getscreen(){
DisplayMetrics dm = new DisplayMetrics();
this.getWindowManager().getDefaultDisplay().getMetrics(dm);
return dm;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
//这个可以判断 上下左右的四个手势动作
float x = e2.getX() - e1.getX();
float y = e2.getY() - e1.getY();
// 限制必须得划过屏幕的1/4才能算划过
float x_limit = getscreen().widthPixels / 4;
float y_limit = getscreen().heightPixels / 4;
float x_abs = Math.abs(x);
float y_abs = Math.abs(y);
if (x_abs >= y_abs) {
// gesture left or right
if (x > x_limit || x < -x_limit) {
if (x > 0) {
// right
Log.e("Tag", "right");
startActivity(new Intent(this,Main2.class));
} else if (x <= 0) {
// left
startActivity(new Intent(this,Main3.class));
Log.e("Tag", "left");
}
}
} else {
// gesture down or up
if (y > y_limit || y < -y_limit) {
if (y > 0) {
// down
Log.e("Tag", "down");
} else if (y <= 0) {
// up
Log.e("Tag", "up");
}
}
}
Log.e("Tag", "判断结束");
return true;
}
//在按下动作时被调用
@Override
public boolean onDown(MotionEvent e) {
return false;
}
}
GestureDetector 中SimpleOnScaleGestureListener&SimpleOnGestureListener 用法
If you only want to listen for a subset it might be easier to extend GestureDetector.SimpleOnGestureListener.
官方推荐一个更简易,更建议使用的一个已实现的方法
适用于单一手势
下面是例子:
public class Main2 extends Activity implements View.OnTouchListener {
private GestureDetector gestureDetector; //手势探测器
private ScaleGestureDetector ScaleGesture;//比率手势探测器
private ImageView image;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
image = (ImageView) findViewById(R.id.image);
//监听这个ImageView组件上的触摸屏时间
image.setOnTouchListener(this);
gestureDetector = new GestureDetector(this, new DefGesture());
ScaleGesture = new ScaleGestureDetector(this,new ScaleGesture());
}
@Override
public boolean onTouch(View v, MotionEvent event) {
gestureDetector.onTouchEvent(event);
ScaleGesture.onTouchEvent(event);
return true; //true 代表可以分发 false 不可以分发
}
}
class DefGesture extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDoubleTap(MotionEvent e) {
Log.e("onDoubleTap", e.getAction() + "");
return super.onDoubleTap(e);
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
Log.e("onDoubleTapEvent", e.getAction() + "");
return super.onDoubleTapEvent(e);
}
}
//SimpleOnScaleGestureListener implements OnScaleGestureListener
class ScaleGesture extends ScaleGestureDetector.SimpleOnScaleGestureListener {//双手指操作
@Override
public boolean onScale(ScaleGestureDetector detector) {
detector.getCurrentSpan();//两点间的距离跨度
detector.getCurrentSpanX();//两点间的x距离
detector.getCurrentSpanY();//两点间的y距离
detector.getFocusX(); //
detector.getFocusY(); //
detector.getPreviousSpan(); //上次
detector.getPreviousSpanX();//上次
detector.getPreviousSpanY();//上次
detector.getEventTime(); //当前事件的事件
detector.getTimeDelta(); //两次事件间的时间差
detector.getScaleFactor(); //与上次事件相比,得到的比例因子
Log.e("getCurrentSpan", detector.getCurrentSpan() + "");
return true;
}
}