本系列文章均为A2BGeek原创,转载务必在明显处注明:
转载自A2BGeek的【Android每周专题】系列,原文链接:http://blog.csdn.net/benbmw2008/article/details/11367631
这篇专题来研究一下Android的触摸屏手势Gesture,Android的手势有两种,一种是View和Activity的(基于触摸屏事件,所以Activity也能添加手势),一种是手写输入法或者一些手机浏览器的快捷手势那样的带笔迹的手势识别。这一点从API文档中就能体现出来:分别有android.view.GestureDetector和android.gesture.Gesture。

我们先来介绍View和Activity的手势,再介绍输入法手势识别。
View和Activity的手势
这一部分想必大家都已经非常熟悉了,现在很多APP都会加入手势来提高交互体验,其中在某个界面向右Fling关闭该界面这一操作貌似成了APP的标配了。废话不多说了,直接进入正题。
为View和Activity加入手势操作的步骤如下:
1、为View或者Activity实现OnGestureListener接口。
2、覆写View或者Activity的OnTouchEvent方法,这里要返回GestureDetector.onTouchEvent()。
3、覆写你需要的手势的回调方法。
这里解释一下各种回调方法的含义:
按下(onDown): 刚刚手指接触到触摸屏的那一刹那,就是触的那一下。
抛掷(onFling): 手指在触摸屏上迅速移动,并松开的动作。
长按(onLongPress): 手指按在持续一段时间,并且没有松开。
滚动(onScroll): 手指在触摸屏上滑动。
按住(onShowPress): 手指按在触摸屏上,它的时间范围在按下起效,在长按之前。
抬起(onSingleTapUp):手指离开触摸屏的那一刹那。
除了这些定义之外,鄙人也总结了一点算是经验的经验吧,在这里和大家分享一下。
任何手势动作都会先执行一次按下(onDown)动作。
长按(onLongPress)动作前一定会执行一次按住(onShowPress)动作。
按住(onShowPress)动作和按下(onDown)动作之后都会执行一次抬起(onSingleTapUp)动作。
长按(onLongPress)、滚动(onScroll)和抛掷(onFling)动作之后都不会执行抬起(onSingleTapUp)动作。
我这里贴上一段代码,大家可以看一下实现的步骤,实验代码和触摸屏事件专题的代码差不多,我就不重复上传了。
package com.example.gesturedemo;
import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.widget.TextView;
public class MyTextView extends TextView implements OnGestureListener {
private GestureDetector mGestureDetector;
public MyTextView(Context context) {
super(context);
// TODO Auto-generated constructor stub
mGestureDetector = new GestureDetector(context, this);
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
mGestureDetector = new GestureDetector(context, this);
}
public MyTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
mGestureDetector = new GestureDetector(context, this);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
DebugTool.log("MyTextView--->dispatchTouchEvent");
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
DebugTool.log("MyTextView--->onTouchEvent");
// int action = event.getAction();
// switch (action) {
// case MotionEvent.ACTION_DOWN:
// DebugTool.log("MyTextView--->onTouchEvent--->DOWN");
// break;
// case MotionEvent.ACTION_MOVE:
// DebugTool.log("MyTextView--->onTouchEvent--->MOVE");
// break;
// case MotionEvent.ACTION_UP:
// DebugTool.log("MyTextView--->onTouchEvent--->UP");
// break;
// }
return mGestureDetector.onTouchEvent(event);
}
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
// TODO Auto-generated method stub
DebugTool.log("MyTextView--->onFling");
return false;
}
@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
}
在OnGestureListener的带返回值的几个回调方法默认返回false的情况下,你会发现Fling手势是识别不到的,这是什么原因呢?这需要用上一专题的知识来解释
http://blog.csdn.net/benbmw2008/article/details/11143893。
大家应该能看出来手势是基于触摸屏事件传递的,对照着上一篇的“默认事件流向”图,读者可以想象其实就是在“MyTextView
onTouchEvent”和“MyRelativeLayout onTouchEvent”之间加一个"MyTextView's GestureDetector onTouchEvent",而"MyTextView's GestureDetector onTouchEvent"返回false,事件还是会继续传递给“MyRelativeLayout onTouchEvent”。解决的办法是什么呢?自然是把OnGestureListener的带返回值的几个回调方法返回true,这样触摸屏事件就被“GestureDetector
onTouchEvent”所消费,看一下日志会更加清楚:
09-08 10:36:10.714: V/gesturedemo(13130): MainActivity--->dispatchTouchEvent
09-08 10:36:10.718: V/gesturedemo(13130): MyRelativeLayout--->dispatchTouchEvent
09-08 10:36:10.722: V/gesturedemo(13130): MyRelativeLayout--->onInterceptTouchEvent
09-08 10:36:10.722: V/gesturedemo(13130): MyTextView--->dispatchTouchEvent
09-08 10:36:10.722: V/gesturedemo(13130): MyTextView--->onTouchEvent
09-08 10:36:10.824: V/gesturedemo(13130): MainActivity--->dispatchTouchEvent
09-08 10:36:10.828: V/gesturedemo(13130): MyRelativeLayout--->dispatchTouchEvent
09-08 10:36:10.832: V/gesturedemo(13130): MyRelativeLayout--->onInterceptTouchEvent
09-08 10:36:10.835: V/gesturedemo(13130): MyTextView--->dispatchTouchEvent
09-08 10:36:10.835: V/gesturedemo(13130): MyTextView--->onTouchEvent
09-08 10:36:10.863: V/gesturedemo(13130): MainActivity--->dispatchTouchEvent
09-08 10:36:10.878: V/gesturedemo(13130): MyRelativeLayout--->dispatchTouchEvent
09-08 10:36:10.886: V/gesturedemo(13130): MyRelativeLayout--->onInterceptTouchEvent
09-08 10:36:10.886: V/gesturedemo(13130): MyTextView--->dispatchTouchEvent
09-08 10:36:10.886: V/gesturedemo(13130): MyTextView--->onTouchEvent
09-08 10:36:10.898: V/gesturedemo(13130): MainActivity--->dispatchTouchEvent
09-08 10:36:10.898: V/gesturedemo(13130): MyRelativeLayout--->dispatchTouchEvent
09-08 10:36:10.898: V/gesturedemo(13130): MyRelativeLayout--->onInterceptTouchEvent
09-08 10:36:10.898: V/gesturedemo(13130): MyTextView--->dispatchTouchEvent
09-08 10:36:10.898: V/gesturedemo(13130): MyTextView--->onTouchEvent
09-08 10:36:10.917: V/gesturedemo(13130): MainActivity--->dispatchTouchEvent
09-08 10:36:10.917: V/gesturedemo(13130): MyRelativeLayout--->dispatchTouchEvent
09-08 10:36:10.917: V/gesturedemo(13130): MyRelativeLayout--->onInterceptTouchEvent
09-08 10:36:10.917: V/gesturedemo(13130): MyTextView--->dispatchTouchEvent
09-08 10:36:10.917: V/gesturedemo(13130): MyTextView--->onTouchEvent
09-08 10:36:10.917: V/gesturedemo(13130): MyTextView--->onFling
Activity的手势实现和View的是一样的,这里就不重复说了,只不过你不用再修改手势回调方法的返回值了。
下面我又突然想到了一个问题,就是手势区域重复了怎么办?举个例子,有一个只包含一个View的Activity,需要实现在View区域向右Fling关闭Activity,向下Fling做别的一些操作,
1、如果逻辑都实现在View上是非常简单的,在onFling中直接判断就可以了。
2、但是有的情况只允许向右Fling的判断实现在Activity中,向下Fling的判断实现在View中(或者相反,总之是分开判断),这个时候又该怎么办?
对于第二种情况,答案还是很有意思的,读者如果感兴趣的话可以发表评论,有营养的评论超过5条后我会将答案的代码下载地址放在文章的最后。
输入法手势识别
在手写输入中,会为每一个字符定义一个特征码,这些特征码都保存在相应的文件中(可能有一个或多个这样的文件),当用户绘制一个描述字符的图形时,系统会为所绘制的图形提取特征码,然后会在保存特征码文件中查找相对应的特征码,如果找到,就会将对应的字符返回。其中,这些文件被称为手势文件。
我们来做一个简单的手势识别APP。
一、首先需要建立手势文件,这里需要借助SDK自带的Sample,大家在Eclipse中File--->New--->Project--->Android--->Android Sample Project,选择GestureBuilder,运行之,建立几个自己的手势,然后把手势文件拿出来即可(每建立一个手势会有一个Toast弹出,告诉你文件的保存路径)。
其实可以想像gestures手势文件中就是一个一个的键值对。
布局文件如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/tv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="@string/hello_world"
android:textSize="24sp" />
<android.gesture.GestureOverlayView
android:id="@+id/gestures"
android:layout_width="200dip"
android:layout_height="200dip"
android:layout_centerInParent="true"
android:background="#33B5E5" >
</android.gesture.GestureOverlayView>
</RelativeLayout>
代码如下:
package com.a2bgeek.gesturedemo2;
import java.util.ArrayList;
import android.os.Bundle;
import android.app.Activity;
import android.gesture.Gesture;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView;
import android.gesture.GestureOverlayView.OnGesturePerformedListener;
import android.gesture.Prediction;
import android.view.Menu;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private TextView mTextView;
private GestureOverlayView mGestureOverlayView;
private GestureLibrary mGestureLibrary;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews() {
mTextView = (TextView) findViewById(R.id.tv1);
mGestureLibrary = GestureLibraries.fromRawResource(
getApplicationContext(), R.raw.gestures);
if (mGestureLibrary.load()) {
mGestureOverlayView = (GestureOverlayView) findViewById(R.id.gestures);
mGestureOverlayView
.addOnGesturePerformedListener(new MyGesturePerformListener());
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private class MyGesturePerformListener implements
OnGesturePerformedListener {
@Override
public void onGesturePerformed(GestureOverlayView overlay,
Gesture gesture) {
// TODO Auto-generated method stub
ArrayList<Prediction> list = mGestureLibrary.recognize(gesture);
if (list.size() > 0) {
//list是mGestureLibrary中可能与gesture匹配的手势集,匹配的程度会有一个score评分。
StringBuilder sb = new StringBuilder();
for (Prediction prediction : list) {
sb.append(prediction.name);
sb.append(":");
sb.append(prediction.score);
sb.append("\n");
}
mTextView.setText(sb.toString());
} else {
Toast.makeText(getApplicationContext(), "没有匹配",
Toast.LENGTH_SHORT).show();
}
}
}
}
好了,今天的内容就到这里了,第一周更新了两篇专题,是个良好的开始,嗯嗯,加油。
分享到:
相关推荐
【Android每周专题】触摸屏手势实验代码 在Android开发中,触摸屏手势是用户与应用程序交互的重要方式之一。本专题将深入探讨如何在Android平台上实现各种触摸手势,以提升应用的用户体验。通过实验代码,我们可以...
【Android每周专题】触摸屏事件实验代码 在Android开发中,触摸屏事件处理是构建用户交互界面的关键部分。本文将深入探讨如何在Android应用中处理触摸事件,通过实验代码来帮助开发者理解这一核心概念。 首先,...
触屏手势识别是指通过检测用户在触摸屏上的连续或独立的手势动作,如滑动、点击、双击、捏合等,将这些动作转化为可识别的操作指令。这种技术使得用户能够以更自然、直观的方式与设备交互,极大地提升了用户体验。 ...
"安卓Android源码——触屏手势识别GestureTest.zip"是一个专注于手势识别的项目,它帮助开发者深入理解如何在Android应用中实现对用户触摸屏幕行为的智能解析。 在Android系统中,触屏手势识别是通过`...
Android系统基于触摸屏设备设计,提供了丰富的触控事件处理机制。主要的触摸事件类有`MotionEvent`,它包含了触摸事件的各种信息,如ACTION_DOWN(手指触摸屏幕)、ACTION_MOVE(手指在屏幕上移动)、ACTION_UP...
Android系统通过`MotionEvent`类来处理触摸屏的输入事件。当用户在屏幕上进行操作时,系统会生成一系列的`MotionEvent`对象,这些对象包含了事件的时间戳、坐标以及事件类型(如ACTION_DOWN、ACTION_UP、ACTION_MOVE...
在安卓(Android)系统中,触屏手势识别是构建用户友好、交互性强的应用程序的关键技术。这份"安卓Android源码——(触屏手势识别).zip"压缩包很可能包含了一个示例项目,展示了如何在Android应用中实现触屏手势的...
总结起来,Android触屏手势识别涉及了触摸事件处理、`GestureDetector`、`ScaleGestureDetector`、`GestureOverlayView`以及自定义手势识别等多个方面。理解并熟练运用这些知识点,可以创建出更加直观、友好的用户...
在Android开发中,触屏手势识别是用户交互的重要组成部分,它允许用户通过各种手势与应用程序进行互动,提高用户体验。这个名为"Android源码——触屏手势识别GestureTest.zip"的压缩包显然包含了与实现这一功能相关...
Android触摸屏手势识别是Android开发中的一个重要组成部分,它允许开发者为应用程序添加更丰富的交互体验。在Android系统中,手势识别主要依赖于`GestureDetector`类和`OnGestureListener`接口。`GestureDetector`类...
QGestureEvent是Qt事件系统的一部分,它包含了在触摸屏上发生的所有手势信息。当用户执行手势时,Qt会生成一个QGestureEvent,并将其发送给相应部件的`gestureEvent()`方法。这个事件包含了所有已识别的手势对象,...
本文将深入探讨Android触摸屏手势的实现原理、常见手势类型以及如何在应用程序中集成手势识别。 首先,Android系统通过MotionEvent类来处理触摸事件。MotionEvent包含了触摸事件的类型(ACTION_DOWN, ACTION_UP, ...
Android触摸屏手势识别是Android系统中一项关键的交互技术,它允许用户通过触摸屏幕执行各种操作,如滑动(Fling)、滚动(Scroll)等,从而提升应用程序的用户体验。在Android开发中,手势识别主要依赖于`...
在Android应用程序开发中,触屏手势识别是提升用户体验的关键技术之一。`GestureTest.zip`这个压缩包文件包含了一个专门用于研究和实践Android触屏手势识别的项目实例,它可以帮助开发者深入理解并掌握这一核心技术...
在Android平台上,触屏手势识别是一项关键的技术,它允许用户通过不同的触摸动作与应用程序进行交互。GestureTest项目是专门用于测试和理解这一功能的一个实例。本文将深入探讨Android中的触屏手势识别及其相关知识...
随着智能手机时代的到来,触摸屏技术逐渐成为主流,传统的物理按键被触摸屏操作所取代。其中,滑动手势因其直观性和便捷性而受到用户的广泛欢迎。本文将深入探讨如何在Android应用中实现滑动切换页面功能,通过具体...
Android基于Listener模式来处理事件,例如触摸屏事件。每个View子类都可以通过`setOnTouchListener()`、`setOnKeyListener()`等方法设置监听器。`OnTouchListener`接口提供了`onTouch()`方法,当用户与View交互时,...