一、手势简介
移动设备大行其道的今天,手势是一个流行词汇,那手势是什么呢?手,是人类各种创造性活动的天然工具,人们天生就会使用手的动作去表达情感,比如人们 会使用握手来表示友好,聋哑人使用一套用手语来代替语言交流,这些都是手势在生活中的应用。可见自古以来手势就是一套特定的语言系统,在人的交流中发挥重 要的作用。从交互上看,手势实际上是一种输入模式。我们现在在直观意义上理解的人机交互是指人与机器之间的互动方式,这种互动方式经历了鼠标、物理硬件、 屏幕触控、远距离的体感操作的逐步发展的过程。
(引用自腾讯CDC-移动设备手势设计初探)
对于开发者而言,如同按钮的点击一样,手势的触发也是一种事件(Event)
。而我们通常将用户的手指或者是能够触发手势的设备(比如触控笔)在能识别手势的设备(如触摸屏)上的触碰动作认为是手势事件。这样的设计能够充分体现移动设备的交互优势,能够让用户以更加自然的方式参与到与应用的交互之中。
下面列举了一些常见的手势操作:
当然,每种手势具体能用来做什么,是由你的应用决定的,但我们推荐你参考一些较新的移动互联网应用开发规范来使得你的应用不那么与世隔绝。
对于一些常见的手势,比如短按
、长按
、双击
、拖拽
等,Android已实现了相应的手势检测,并为其提供了相应的API(主要是监听器)来满足开发需要。这些手势将在本实验被详细的介绍。
而另外一些非常规的手势,例如在屏幕上画个圈、画一个特殊的几何形状等,Android没有为它们提供特定的手势检测,但允许开发者自己来添加手势,通过与手势相似度相关的API来负责识别。
二、在Android上实现手势监听
在Android中,是由GestureDetector
类来负责手势的检测,每一个GestureDetector
类的实例都代表一个手势监听器。我们在为按钮设置点击事件监听器时会用到OnClickListener
,同样,你在创建手势监听器时也需要一个类似的OnGestureListener
实例。
在OnGestureListerner
接口里面,有以下事件处理的方法可供你调用:
-
boolean onDown(MotionEvent e)
:当用户在屏幕上按下时会触发该方法,但在移动或抬起手指时不会触发。-
void onShowPress(MotionEvent e)
:当用户在屏幕上按下,并且既没有移动有没有抬起手指时,会触发该方法。一般通过该方法告知用户他们的动作已经被识别到了,你可以高亮某个元素来提醒他们。-
boolean onSingleTapUp(MotionEvent e);
:当用户在屏幕上轻击时(通常是指点击屏幕的时间很短)会触发该方法。-
boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);
:当用户在屏幕上发起滚动的手势时会触发该方法。参数中的e1
指第一个按下开始滚动的动作事件,e2
指触发当前这个方法的移动动作的事件,distanceX
和distanceY
则分别触发onScroll
方法期间的X、Y轴上的滚动距离,而不是指e1
和e2
两个事件发生直接的距离。-
void onLongPress(MotionEvent e);
:当用户在屏幕上持续地长按时会触发该方法。-
boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
:当用户在屏幕上持续地按下并且有“抛”的动作时,会触发该方法。对于该事件的理解,你可以体会一下按住一个图标然后把它扔到某个地方的感觉。参数中的e1
指第一个按下的动作事件,e2
指触发当前这个方法的“猛扔”动作的事件,velocityX
和velocityY
则分别触发onFling
方法期间X、Y轴上的移动速度。
如果你翻阅这些API的源代码,你还能发现还有一个名为OnDoubleTapListener
的接口,显然是双击事件的一个监听器,它包含了下面这些方法。
-
boolean onSingleTapConfirmed(MotionEvent e)
:当用户在屏幕上单击是会触发此方法,与上面的onSingleTapUp
方法不同的地方在于,该方法只会在监听器确定了用户在第一次单击后不会触发双击事件时才会被触发。-
boolean onDoubleTap(MotionEvent e)
:当用户在屏幕上双击时会触发此方法。这里的按下动作事件指的时双击中的第一次触击。-
boolean onDoubleTapEvent(MotionEvent e)
:在双击事件发生时会触发此方法,包括了按下、移动和抬起事件。
掌握了上面这些方法后,我们通过一个实例来实际应用一下:
实验步骤主要有:
- (若你已在第二小节完成,请跳至下一步)使用Android Studio创建应用项目
GesturePractice
,包名为com.shiyanlou.android.gesturepractice
,基于Android 5.1
。同时添加MainActivity
及其布局资源文件。在项目创建好之后再创建并打开AVD
模拟器(镜像选择API22:Android 5.1.1
)。 - 在
res/layout/activity_main.xml
资源文件放入一个文本标签。 - 在
MainActivity.java
中,为这个Activity添加手势监听相关的代码。 - 编译并运行这个应用,等待应用安装至模拟器,在模拟器中试用该应用。
下面是res/layout/avtivity_main.xml
中的布局:
<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:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <TextView android:id="@+id/textView_domain" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:text="Shiyanlou.com" android:textColor="#11AA8C" android:textSize="40dp"/> <TextView android:id="@+id/textView_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/textView_domain" android:layout_centerHorizontal="true" android:text="Gesture Practice" android:textColor="#000000" android:textSize="40dp"/> <TextView android:id="@+id/textView_helloWorld" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/bt_scroll" android:layout_centerHorizontal="true" android:layout_marginTop="50dp" android:text="Hello World!" android:textColor="#000000" /> <Button android:id="@+id/bt_scroll" android:layout_width="match_parent" android:layout_height="100dp" android:layout_below="@id/textView_title" android:layout_marginTop="0dp" android:text="滑动我"/> </RelativeLayout>
下面是MainActivity.java
中的源代码:
package com.earl.leangesturedetector; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.widget.Button; import android.widget.TextView; public class MainActivity extends AppCompatActivity implements GestureDetector.OnGestureListener {//在这个类中需要实现OnGestureListener相关的接口 private Button bt_scroll; private TextView textview; //声明一个文本标签 private float fontSize = 30; //声明一个用于指示字体大小的变量,初始值为30 GestureDetector detector; //声明一个手势检测器对象 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bt_scroll = (Button) findViewById(R.id.bt_scroll); textview = (TextView) findViewById(R.id.textView_helloWorld); textview.setTextSize(fontSize);//实例化这个文本标签并为其设置最初始的大小 detector = new GestureDetector(this, this);//实例化这个手势检测器对象 //把事件都放在控件上 bt_scroll.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { return detector.onTouchEvent(motionEvent); } }); } // //下面实现的这些接口负责处理所有在该Activity上发生的触碰屏幕相关的事件 // @Override // public boolean onTouchEvent(MotionEvent e) { // return detector.onTouchEvent(e); // } @Override public boolean onDown(MotionEvent motionEvent) { return false; } @Override public void onShowPress(MotionEvent motionEvent) { } @Override public boolean onSingleTapUp(MotionEvent motionEvent) { return false; } @Override public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float distanceX, float distanceY) { if (distanceY >= 0) { //和distanceX一样,distanceY这个参数有正有负,我们对该数值所处的不同范围分别处理 //向上滚动的手势可以让文本标签的字号变小 if (fontSize > 10) fontSize -= 5; //加一个判断的目的是防止字号太小或者太大,下同 textview.setTextSize(fontSize); //将计算好的字号应用到文本标签上 } else { //向下滚动的手势可以让文本标签的字号变小 if (fontSize < 60) fontSize += 5; textview.setTextSize(fontSize); } return true; } @Override public void onLongPress(MotionEvent motionEvent) { } @Override public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) { return false; } }
检查一下代码,编译并运行该应用,在模拟器上可以看到应用的主界面:
此时你在屏幕上尝试做出一些手势,就能看到下方的Toast显示刚刚触发了哪些方法。
向上或向下滚动,你就可以改变Hello World
的字号大小了。