识别器GestureDetector基本介绍
当用户触摸屏幕的时候,会产生许多手势,例如down,up,scroll,filing等。一般情况下,我们可以通过View或Activity的onTouchEvent,或实现OnTouchListener接口后通过onTouch方法,处理一些touch事件,但是这个方法太过简单,如果需要处理一些复杂的手势,用这个接口就会很麻烦(因为我们要自己根据用户触摸的轨迹去判断是什么手势)。为此,Android 给我们提供了GestureDetector类(Gesture:手势,Detector:识别),通过这个类我们可以识别很多的手势,主要是通过他的onTouchEvent方法完成不同手势的识别。 虽然他能识别手势,但是不同的手势要怎么处理,还是给程序员自己要实现的。
注意: 默认情况下,GestureDetector是监听不到MotionEvent事件的,也即GestureDetector的onTouchEvent方法是不会被调用的,若要被调用,必须满足两个条件
- ①在View的onTouchEvent()方法中,须将MotionEvent事件手动【传】给GestureDetector
- ②若View设置了.setOnTouchListener()监听器,则其onTouch()的返回值还须是【false】,或者在onTouch()中将MotionEvent事件手动【传】给GestureDetector
识别器ScaleGestureDetector基本介绍
ScaleGestureDetector是Android2.2 新增的类,其能使 Views 通过接收到的 MotionEvents ,检测包括多点触摸在内的手势变化信息,当检测到此类信息后,监听器OnScaleGestureListener 便会调用相应的回调方法通知用户,其最简单常用的应用场景就是使用双指缩放图片。 注意,ScaleGestureDetector是直接继承自object的,并非GestureDetector的子类。 监听器OnScaleGestureListener回调方法有onScale(ScaleGestureDetector) 、onScaleBegin、onScaleEnd ScaleGestureDetector中定义的公共方法:
- public float getCurrentSpan () 返回手势过程中,组成该手势的两个触点的当前距离。
- public long getEventTime () 返回事件被捕捉时的时间。
- public float getFocusX () 返回当前手势焦点的 X 坐标。 如果手势正在进行中,焦点位于组成手势的两个触点之间。 如果手势正在结束,焦点为仍留在屏幕上的触点的位置。若 isInProgress() 返回 false,该方法的返回值未定义。
- public float getFocusY () 返回当前手势焦点的 Y 坐标。
- public float getPreviousSpan () 返回手势过程中,组成该手势的两个触点的前一次距离。
- public float getScaleFactor () 返回从前一个伸缩事件至当前伸缩事件的伸缩比率。该值定义为 getCurrentSpan() / getPreviousSpan()。
- public long getTimeDelta () 返回前一次接收到的伸缩事件距当前伸缩事件的时间差,以毫秒为单位。
- public boolean isInProgress () 如果手势处于进行过程中,返回 true。否则返回 false。
手势监听器SimpleOnGestureListeren
我们只需要继承SimpleOnGestureListener重载自己需要监听的手势即可 public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener {}
OnGestureListener的监听事件
- 按下(onDown): 刚刚手指接触到触摸屏的那一刹那,就是触的那一下
- 抛掷(onFling): 手指在触摸屏上迅速移动,并松开的动作,onDown---onScroll---onScroll---…onFling
- 长按(onLongPress): 手指按在持续一段时间,并且没有松开
- 滚动(onScroll): 手指在触摸屏上滑动,onDown---onScroll---onScroll---…onScroll
- 按住(onShowPress): 手指按在触摸屏上,在按下起效,在长按前失效,onDown->onShowPress->onLongPress
- 抬起(onSingleTapUp):手指离开触摸屏的那一刹那
OnDoubleTapListener的监听事件
- onDoubleTap,双击的【第二下】down时触发(只执行一次)
- onDoubleTapEvent,双击的【第二下】down和up都会触发(执行次数不确定)
- onSingleTapConfirmed单击确认,即很快的按下并抬起,但并不连续点击第二下
注意:
- onSingleTapConfirmed(单击)和onSingleTapUp都是在down后既没有滑动onScroll,又没有长按onLongPress时, up 时触发的
- 非常快的点击一下:onDown->onSingleTapUp->onSingleTapConfirmed
- 稍微慢点的点击一下:onDown->onShowPress->onSingleTapUp->onSingleTapConfirmed(最后一个不一定会触发)
演示代码-在Activity中使用
上面的图片是添加了GestureDetector和ScaleGestureDetector的ImageView,并且在【onTouchEvent】方法中将事件传递给手势识别器,且返回【true】下面的图片是在上面图片基础上注册了【OnTouchListener】,若在其【onTouch】方法中返回【true】,则就会导致其注册的手势识别器全部失效!我们为Activity自身注册了GestureDetector和ScaleGestureDetector,并且在其【onTouchEvent】方法中将事件传递给手势识别器,返回值使用默认逻辑值 public class MainActivity extends Activity { private GestureDetector mGestureDetector;//用于Activity自身的单击和双击事件手势识别器 private ScaleGestureDetector mScaleGestureDetector;//用于Activity自身的缩放事件手势识别器 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MyImageView myImageView = (MyImageView) findViewById(R.id.iv); myImageView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return true;//返回值要为false,或者直接在此onTouch()中将MotionEvent事件手动传给GestureDetector,才能使手势识别器生效 } }); //************************************************************************************************************************** mGestureDetector = new GestureDetector(this, new SimpleOnGestureListener() { @Override //监测双击事件 public boolean onDoubleTap(MotionEvent e) { Log.e("Activity-手势", "onDoubleTap"); return super.onDoubleTap(e); } }); mScaleGestureDetector = new ScaleGestureDetector(this, new SimpleOnScaleGestureListener() { @Override //监测缩放 public boolean onScale(ScaleGestureDetector detector) { DecimalFormat df = new DecimalFormat("0.00");//格式化float Log.e("Activity-缩放", "onScale," + df.format(detector.getScaleFactor()) + "-" + //缩放因子,两指靠拢时小于1 df.format(detector.getFocusX()) + "-" + df.format(detector.getFocusY()));//中心点坐标 return super.onScale(detector); } }); } //************************************************************************************************************************** @Override //重写屏幕触摸事件onTouchEvent,将触摸事件传给GestureDetector public boolean onTouchEvent(MotionEvent event) { try { //在onTouchEvent方法中可以完成所有GestureDetector的操作,因为他们都只需要一个MotionEvent的参数 Log.e("Activity-多点触摸", "onTouchEvent" + spacing(event)); } catch (Exception e) { } mGestureDetector.onTouchEvent(event); mScaleGestureDetector.onTouchEvent(event); return super.onTouchEvent(event); } /** * 返回两个点之间的距离 */ private float spacing(MotionEvent event) { float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); return FloatMath.sqrt(x * x + y * y); } }
演示代码-在View中使用
public class MyImageView extends ImageView { private GestureDetector mGestureDetector;//单击和双击事件手势识别 private ScaleGestureDetector mScaleGestureDetector;//缩放事件手势识别 public MyImageView(Context context) { this(context, null); } public MyImageView(Context context, AttributeSet attr) { super(context, attr); mGestureDetector = new GestureDetector(context, new MyGestureListener()); mScaleGestureDetector = new ScaleGestureDetector(context, new MyScaleGestureListener()); } @Override public boolean onTouchEvent(MotionEvent event) { mGestureDetector.onTouchEvent(event); mScaleGestureDetector.onTouchEvent(event); //return super.onTouchEvent(event);//不管返回值是什么,都能接收down事件,都能触发onDown、onShowPress、onLongPress return true;//但只有返回true才能继续接收move,up等事件,也才能响应ScaleGestureDetector事件及GestureDetector中与move,up相关的事件 } //************************************************************************************************************************** private class MyScaleGestureListener extends SimpleOnScaleGestureListener { @Override public boolean onScale(ScaleGestureDetector detector) { Log.e("view-缩放", "onScale," + detector.getScaleFactor()); return super.onScale(detector); } @Override public boolean onScaleBegin(ScaleGestureDetector detector) { Log.e("view-缩放", "onScaleBegin"); return super.onScaleBegin(detector); } @Override public void onScaleEnd(ScaleGestureDetector detector) { Log.e("view-缩放", "onScaleEnd"); } } //************************************************************************************************************************** private class MyGestureListener extends SimpleOnGestureListener { @Override //双击的【第二下】Touch down时触发(只执行一次) public boolean onDoubleTap(MotionEvent e) { Log.e("view-手势", "onDoubleTap"); return super.onDoubleTap(e); } @Override //双击的【第二下】Touch down和up都会触发(执行次数不确定)。 public boolean onDoubleTapEvent(MotionEvent e) { Log.e("view-手势", "onDoubleTapEvent"); return super.onDoubleTapEvent(e); } @Override //Touch down时触发 public boolean onDown(MotionEvent e) { Log.e("view-手势", "onDown"); return super.onDown(e); } @Override //onScroll一点距离后,【抛掷时】触发(若是轻轻的、慢慢的停止活动,而非抛掷,则很可能不触发) //参数为手指接触屏幕、离开屏幕一瞬间的动作事件,及手指水平、垂直方向移动的速度,像素/秒 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { Log.e("view-手势", "onFling"); if ((e2.getRawX() - e1.getRawX()) > 100) { Log.e("view-手势", "onFling-从左到右滑"); return true; } return super.onFling(e1, e2, velocityX, velocityY); } @Override //Touch了不移动一直Touch down时触发 public void onLongPress(MotionEvent e) { Log.e("view-手势", "onLongPress"); super.onLongPress(e); } @Override //Touch了滑动时触发,e1代表触摸时的事件,是不变的,e2代表滑动过程中的事件,是时刻变化的 //distance是当前event2与上次回调时的event2之间的距离,代表上次回调之后到这次回调之前移动的距离 public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { Log.e("view-手势", "onScroll-" + (int) e1.getX() + "-" + (int) e2.getX() + "-" + (int) distanceX + "-" + (int) distanceY); return super.onScroll(e1, e2, distanceX, distanceY); } @Override //Touch了还没有滑动时触发 public void onShowPress(MotionEvent e) { Log.e("view-手势", "onShowPress"); super.onShowPress(e); } @Override //在touch down后又没有滑动(onScroll),又没有长按(onLongPress),然后Touchup时触发。 public boolean onSingleTapConfirmed(MotionEvent e) { Log.e("view-手势", "onSingleTapConfirmed"); return super.onSingleTapConfirmed(e); } @Override //在touch down后又没有滑动(onScroll),又没有长按(onLongPress),然后Touchup时触发。 public boolean onSingleTapUp(MotionEvent e) { Log.e("view-手势", "onSingleTapUp"); return super.onSingleTapUp(e); } } }
布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#1234" android:orientation="vertical" > <com.bqt.test.MyImageView android:layout_width="match_parent" android:layout_height="150dp" android:background="#10ff" android:src="@drawable/ic_launcher" /> <com.bqt.test.MyImageView android:id="@+id/iv" android:layout_width="match_parent" android:layout_height="150dp" android:background="#1f00" android:src="@drawable/ic_launcher" /> </LinearLayout>
时间: 2024-11-13 08:14:31