1 手势检测工具
在前面的章节我们讲到过触摸事件:onTouch(),它是一切手势的开始,所以根据onTouch
的几种事件类型我们可以判断出用户的各种手势,但是对于一些相对复杂的手势(比如缩放、旋转、双击等)判断起来会比较麻烦。不过这些都不用担心Android 系统为我们提供了一个叫GestureDetector
的工具类,通过它我们可以轻松的接收到用户的各种复杂手势。
GestureDetector
的使用方法非常简单,首先创建一个类继承自GestureDetector.SimpleOnGestureListener
,然后覆写其中需要监听的事件方法,如下:
GestureDetector mGesture;mGesture = new GestureDetector(this, new Gesture());
class Gesture extends GestureDetector.SimpleOnGestureListener{
public boolean onSingleTapUp(MotionEvent ev) {
}
public void onLongPress(MotionEvent ev) {
}
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
}
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
}}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
2 GestureListener 相关事件
Gesture 支持很多复杂的手势处理,基本上处理手势用它就没错了。这里挑几个最常见的进行详细的讲解,其余的也大同小异。
- onDown: 触摸事件,同
onTouch
事件当中的ACTION_DOWN
,所有手势的起点 - onSingleTapUp: 单击
- onLongPress: 长按
- onScroll: 滚动
- onFling: 手指快速滚动,并离开屏幕,在屏幕继续滚动的时候触发
3 手势的处理方式
在写好了第 1 小节的代码之后,关键就是去实现事件处理代码了,点击、长按等事件都比较好理解,这里以缩放手势为例讲解一下具体的手势处理逻辑。
3.1 缩放处理工具类
缩放的手势处理是通过ScaleGestureDetector
来实现的,首先创建一个ScaleGestureDetector
:
ScaleGestureDetector scaleGestureDetector;scaleGestureDetector = new ScaleGestureDetector(this, new ScaleListener());
构造器需要传入两个参数,一个是上下文 context,一个是缩放时间监听器。所以,在此之前我们还需要创建一个ScaleListener
,然后覆写OnTouchEvent(MotionEvent e)
,并且在OnTouchEvent
中将触摸事件传递给 ScaleGestureDetector,代码如下:
public boolean onTouchEvent(MotionEvent ev) {
SGD.onTouchEvent(ev);
return true;}private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scale = detector.getScaleFactor();
return true;
}}
3.2 手势处理中常用的系统方法
在处理手势的过程中,我们还会调用一些系统方法来辅助完成事件处理,主要有以下几个:
- getEventTime():
获取事件发生的时间戳 - getFocusX():
获取当前手势焦点的 X 轴坐标 - getFocusY():
获取当前手势焦点的 Y 轴坐标 - getTimeDelta():
获取两次缩放时间的时间差 - isInProgress():
判断当前是否正处理缩放过程中 - onTouchEvent(MotionEvent event):
接收系统触摸事件,并分发到相应的监听器中
4 手势处理示例
本节通过GestureDetector
完成一个类似微信聊天中的大图缩放功能,即通过双指往外或者向内的手势来控制图片的放大、缩小。
4.1 编写布局文件
布局文件非常简单,核心就是一个 ImageView,用来承载我们缩放的目标图片。需要注意的是,这里要将图片的 scaleType
设置成“matrix”,用于后续做缩放:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="20dp"
tools:context=".MainActivity">
<TextView
android:id="@+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:text="手势处理示例"
android:textSize="35sp" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textview"
android:layout_centerHorizontal="true"
android:text="慕课 Android 教程"
android:textColor="#ff7aff24"
android:textSize="35dp" />
<ImageView
android:id="@+id/imageView"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_below="@+id/textView"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:scaleType="matrix"
android:src="@drawable/avatar" />
</RelativeLayout>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
4.2 手势处理逻辑编写
- 第一步: 首先创建一个
ScaleListener
,覆写onScale
方法来接收缩放手势; - 第二步: 然后创建
ScaleGestureDetector
,构造器传入 context 对象及刚刚创建的ScaleListener
对象; - 第三步: 接着覆写
onTouchEvent(MotionEvent ev)
,调用 ScaleGestureDetector 的onTouchEvent()
方法,传入 MotionEvent,这样就把触摸事件传递给了ScaleGestureDetector
,后续的整个缩放手势就全权交给ScaleGestureDetector
来处理。 - 第四步: 最后我们只需要在
onScale()
中完成我们的图片缩放逻辑即可。
package com.emercy.myapplication;import android.app.Activity;import android.graphics.Matrix;import android.os.Bundle;import android.view.MotionEvent;import android.view.ScaleGestureDetector;import android.widget.ImageView;public class MainActivity extends Activity {
private ImageView iv;
private Matrix matrix = new Matrix();
private float scale = 1f;
private ScaleGestureDetector mDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv = findViewById(R.id.imageView);
mDetector = new ScaleGestureDetector(this, new ScaleListener());
}
public boolean onTouchEvent(MotionEvent ev) {
mDetector.onTouchEvent(ev);
return true;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
scale *= detector.getScaleFactor();
scale = Math.max(0.1f, Math.min(scale, 5.0f));
matrix.setScale(scale, scale);
iv.setImageMatrix(matrix);
return true;
}
}}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
我们用双指向外或者向内滑动,就可以看到“照骗”会跟随我们的手势而放大/缩小,整个流程非常顺滑无污染,欢迎自行编译体验。
5 小结
本节介绍了一个非常强大的手势处理工具——GestureDetector,如果不使用它,我们需要自行监听onTouch
事件,然后结合“DOWN”、“MOVE”、“UP”等等各种不同的 onTouch 事件组合起来才能检测出一些复杂的手势,这一切 GestureDetector 都帮助我们实现了。学完这一章,我们只需要按照几个简单的步骤就可以进行复杂手势的监听,从此可以释放双手,来创造更多复杂的事件让用户更加顺滑的使用了。