Android基础系列 - 手势识别运用
Posted SingleShu888
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android基础系列 - 手势识别运用相关的知识,希望对你有一定的参考价值。
android开发中,几乎所有的事件都会和用户进行交互,而最多的交互形式就是手势了。也有很多手势三方的库。比如 android-gesture-detectors 、AndroidPdfViewer(这个库支持pdf文档显示,支持手势),这些三方库都是不错的手势识别。不过今天我们来看看谷歌提供的原生手势识别的相关类和使用方式,以及一些简单的运用。
手势呢,大概分为两个大类别,一种是左滑右滑,Google提供了手势检测并提供了相应的监听器,另一种就是画个圆圈,正方形登特殊手势。这种手势需要开发者自己添加手势识别,并提供了相关的API识别用户手势。GestureDetector,提供了简单手势识别和监听回调。GestureDetector谷歌官方文档地址:https://developer.android.com/reference/android/view/GestureDetector.html。GestureDetector主要使用在于手势的的回调监听, GestureDetector.OnGestureListener, GestureDetector.SimpleOnGestureListener,GestureDetector.OnDoubleTapListener。这些监听器才是关键,后面慢慢会讲到。
那么先看看GestureDetector的方法。
isLongpressEnabled (),是否允许长点击
onTouchEvent(MotionEvent ev) ,拦截事件进行处理。比如在哪个Activity设置手势识别,那么就需要重写该Activity的onTouchEvent。将事件处理转交给GestureDetetor。
setIsLongpressEnabled(boolean isLongpressEnabled) ,设置是否允许长点击。
setOnDoubleTapListener(GestureDetector.OnDoubleTapListener onDoubleTapListener) ,设置双点击事件回调监听。
GestureDetector的方法,大概也就这些了。关键在于这些手势识别的接口,那么对这些接口的触发以及意义,都挨着使用一次。
GestureDetector.OnGestureListener
这个是常用的接口,作用手势识别的回调。它所有的方法以及意义。
OnDown(MotionEvent e):用户按下屏幕就会触发;
onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) ,滑屏,用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发 参数解释: e1:第1个ACTION_DOWN MotionEvent e2:最后一个ACTION_MOVE MotionEvent velocityX:X轴上的移动速度,像素/秒 velocityY:Y轴上的移动速度,像素/秒。
onLongPress(MotionEvent e) ,长按触摸屏,超过一定时长,就会触发这个事件 触发顺序: onDown->onShowPress->onLongPress。
onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) ,在屏幕上拖动事件。无论是用手拖动view,或者是以抛的动作滚动,都会多次触发,这个方法 在ACTION_MOVE动作发生时就会触发 滑屏:手指触动屏幕后,稍微滑动后立即松开 onDown—–》onScroll—-》onScroll—-》onScroll—-》………—–>onFling 拖动 onDown——》onShowPress —》onScroll—-》onScroll——》onFiling 可见,无论是滑屏,还是拖动,影响的只是中间OnScroll触发的数量多少而已,最终都会触发onFling事件!
onShowPress(MotionEvent e) ,如果是按下的时间超过瞬间,而且在按下的时候没有松开或者是拖动的,那么onShowPress就会执行。这个时间是底层封装,设定的。开发者在应用层只需应用,不必知晓时间设定以及原理。
onSingleTapUp(MotionEvent e) ,顾名思义,一次单独的轻击抬起操作,也就是轻击一下屏幕,立刻抬起来,才会有这个触发,当然,如果除了Down以外还有其它操作,那就不再算是Single操作了,所以也就不会触发这个事件 触发顺序: 点击一下非常快的(不滑动)Touchup: onDown->onSingleTapUp->onSingleTapConfirmed 点击一下稍微慢点的(不滑动)Touchup: onDown->onShowPress->onSingleTapUp->onSingleTapConfirmed。
这些方法就是在用户一些基本手势交互的时候回调。那么写一个简单实例来看看。
public class MainActivity extends AppCompatActivity implements GestureDetector.OnGestureListener
GestureDetector detector;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
detector = new GestureDetector(this,this);
detector.setIsLongpressEnabled(true);
//重写Activity的onTouchEvent,将Activity的事件
@Override
public boolean onTouchEvent(MotionEvent event)
return detector.onTouchEvent(event);
// 用户轻触触摸屏,由1个MotionEvent ACTION_DOWN触发
@Override
public boolean onDown(MotionEvent motionEvent)
Log.i("tag00", "================================");
Log.i("tag00", "onDown");
return false;
/*
* 用户轻触触摸屏,尚未松开或拖动,由一个1个MotionEvent ACTION_DOWN触发
* 注意和onDown()的区别,强调的是没有松开或者拖动的状态
*
* 而onDown也是由一个MotionEventACTION_DOWN触发的,但是他没有任何限制,
* 也就是说当用户点击的时候,首先MotionEventACTION_DOWN,onDown就会执行,
* 如果在按下的瞬间没有松开或者是拖动的时候onShowPress就会执行,如果是按下的时间超过瞬间
* (这块我也不太清楚瞬间的时间差是多少,一般情况下都会执行onShowPress),拖动了,就不执行onShowPress。
*/
@Override
public void onShowPress(MotionEvent motionEvent)
Log.i("tag00", "onShowPress");
// 用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发
// 轻击一下屏幕,立刻抬起来,才会有这个触发
// 从名子也可以看出,一次单独的轻击抬起操作,当然,如果除了Down以外还有其它操作,那就不再算是Single操作了,所以这个事件 就不再响应
@Override
public boolean onSingleTapUp(MotionEvent motionEvent)
Log.i("tag00", "onSingleTapUp");
return false;
// 用户按下触摸屏,并拖动,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE触发
@Override
public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1)
Log.i("tag00", "onScroll");
return false;
// 用户长按触摸屏,由多个MotionEvent ACTION_DOWN触发
@Override
public void onLongPress(MotionEvent motionEvent)
Log.i("tag00", "onLongPress");
// 用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发
@Override
public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1)
Log.i("tag00", "onFling");
return false;
我的手势依次是:
1、轻触,快速拿起。(1~2S)
2、稍长按,再拿起。(4~6S)
3、长按,再拿起。(8S~)
4、从左至右滑动,再拿起,类似翻页。
5、画圆圈。
I/tag00: ================================
I/tag00: onDown
I/tag00: onSingleTapUp
I/tag00: ================================
I/tag00: onDown
I/tag00: onShowPress
I/tag00: onSingleTapUp
I/tag00: ================================
I/tag00: onDown
I/tag00: onShowPress
I/tag00: onLongPress
I/tag00: ================================
I/tag00: onDown
I/tag00: onScroll
I/tag00: onScroll
I/tag00: onScroll
I/tag00: onScroll
I/tag00: onScroll
I/tag00: onScroll
I/tag00: onScroll
I/tag00: onFling
I/tag00: ================================
I/tag00: onDown
I/tag00: onShowPress
I/tag00: onScroll
I/tag00: onScroll
I/tag00: onFling
GestureDetector.OnDoubleTapListener
双击监听接口,方法如下
onSingleTapConfirmed(MotionEvent e):单 击事件。用来判定该次点击是SingleTap而不是DoubleTap,如果连续点击两次就是DoubleTap手势,如果只点击一次,系统等待一段时 间后没有收到第二次点击则判定该次点击为SingleTap而不是DoubleTap,然后触发 SingleTapConfirmed事件。触发顺序 是:OnDown->OnsingleTapUp->OnsingleTapConfirmed ,关于 onSingleTapConfirmed和onSingleTapUp的一点区别: OnGestureListener有这样的一个方法onSingleTapUp,和onSingleTapConfirmed容易混淆。二者的区别 是:onSingleTapUp,只要手抬起就会执行,而对于onSingleTapConfirmed来说,如果双击的话,则 onSingleTapConfirmed不会执行。
onDoubleTap(MotionEvent e):双击事件
onDoubleTapEvent(MotionEvent e):双击间隔中发生的动作。指触发onDoubleTap以后,在双击之间发生的其它动作,包含down、up和move事件。
双击所对应的触发事件顺序:
轻轻单击一下,对应的事件触发顺序为:
GestureDetector.SimpleOnGestureListener
它与前两个不同的是:
1、这是一个类,在它基础上新建类的话,要用extends派生而不是用implements继承!
2、 OnGestureListener和OnDoubleTapListener接口里的函数都是强制必须重写的,即使用不到也要重写出来一个空函数但在 SimpleOnGestureListener类的实例或派生类中不必如此,可以根据情况,用到哪个函数就重写哪个函数,因为 SimpleOnGestureListener类本身已经实现了这两个接口的所有函数,只是里面全是空的而已。
介绍的差不多了,那么先来小试牛刀。
package com.example.administrator.myapplication;
import android.app.Activity;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.widget.ImageView;
/**
* 手势识别类
* 图片切换显示,实现接口OnGestureListener
* @author Administrator
*
*/
public class MyGestrueTest extends Activity implements OnGestureListener
/**手势管理器*/
private GestureDetector detector;
/**图片资源数组*/
private int [] imageId;
/**图片视图*/
private ImageView imageView ;
private ImageView[] imgView;
/**图片下标计数器*/
private int count=0;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_gestrue_test);
//创建手势管理器
detector = new GestureDetector(this);
//得到图片视图
imageView=(ImageView) findViewById(R.id.image_gestrue);
//得到图片资源的Id
imageId = new int[]
R.drawable.timg,
R.drawable.index,
R.drawable.index1,
R.drawable.img3,
R.drawable.img4;
//得到图片视图 ImageView
imgView = new ImageView []
(ImageView) findViewById(R.id.small_image1),
(ImageView) findViewById(R.id.small_image2),
(ImageView) findViewById(R.id.small_image3),
(ImageView) findViewById(R.id.small_image4),
(ImageView) findViewById(R.id.small_image5);
@Override
public boolean onTouchEvent(MotionEvent event)
//将touch事件交给手势管理器来处理
return detector.onTouchEvent(event);
@Override
public boolean onDown(MotionEvent e)
return false;
/**
* 手势滑动触发的事件
*/
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY)
//从右往左移动
if(e1.getX()-e2.getX()>50)
//下标++
count++;
if(count<=4)
//切换到下一张
imageView.setImageResource(imageId[count]);
imgView[count].setImageResource(R.drawable.ic_launcher1);
imgView[count-1].setImageResource(R.mipmap.ic_launcher);
else
//滑动到最后一张,该方向不会再滑动,就停留在最后一张
count=4;
imageView.setImageResource(imageId[count]);
//从左往右移动
if(e1.getX()-e2.getX()<50)
count--;
if(count>=0)
imageView.setImageResource(imageId[count]);
imgView[count].setImageResource(R.drawable.ic_launcher1);
imgView[count+1].setImageResource(R.mipmap.ic_launcher);
else
count=0;
imageView.setImageResource(imageId[count]);
return false;
@Override
public void onLongPress(MotionEvent e)
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY)
return false;
@Override
public void onShowPress(MotionEvent e)
@Override
public boolean onSingleTapUp(MotionEvent e)
return false;
布局代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000">
<LinearLayout
android:id="@+id/my_geture_test_1"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="@+id/image_gestrue"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/timg" >
</ImageView>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center_horizontal"
android:layout_marginBottom="30dp"
>
<ImageView
android:id="@+id/small_image1"
android:padding="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"
>
</ImageView>
<ImageView
android:id="@+id/small_image2"
android:padding="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher" >
</ImageView>
<ImageView
android:id="@+id/small_image3"
android:padding="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher" >
</ImageView>
<ImageView
android:id="@+id/small_image4"
android:padding="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher" >
</ImageView>
<ImageView
android:id="@+id/small_image5"
android:padding="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher" >
</ImageView>
</LinearLayout>
</RelativeLayout>
效果:
可以发现,并没有使用ViewPager这样的控件,虽然没有左右滑动的效果,那个可以在后期优化加上,这里只是做个简单的例子。所以没做太多的优化,毕竟时间有限啊。这是简单的手势识别了。谷歌还提供了自定义手势,通过GestureOverlayView和GestureLibrary增加自定义手势。还提供了缩放手势的识别类ScaleGestureDetector 。之后有时间会继续介绍手势相关。觉得有用,顶一下呗,整理这些内容也不容易~挺花时间的。谢谢大家。
以上是关于Android基础系列 - 手势识别运用的主要内容,如果未能解决你的问题,请参考以下文章
Android应用开发基础篇(13)-----GestureDetector(手势识别)
快速推迟手势识别器(UISwipeGestureRecognizer)