第19天 Android Touch事件学习 6 手势识别
来源:互联网 发布:网络技术交流 编辑:程序博客网 时间:2024/05/22 01:28
触摸事件学习系列文章详见:
《Android Touch事件学习系列汇总》
上一篇分析了View.onTouchEvent源码,发现点击与长按事件处理的原理,但是如果自定义控件需要其他手势呢?假如需要判断滚动事件,之前学习到的代码提供不了帮助,当前也可以自己根据ACTOIN与当前触摸位置来进行判断(如果想自定义滚动事件可以参考ListView的源码),不过Android系统提供了工具类来支持这些手势。
以下仅仅是演示如何使用,并没有列出所有支持的手势,完整的详见官方文档《SimpleOnGestureListener》 ,也可以阅读其源码学习如何判断各种手势。
一、 效果图
二、代码
在Android中自定义控件通常都会涉及到触摸手势,需要判断用户是点击、滑动、Fling、按下等状态,当前这些都可以通过自己在onTouchEvent中通过MotionEvent回调参数判断得到,但是也可以使用Android系统提供的辅助类SimpleOnGestureListener,以下是继承自此类,主要目的是为了观察各个回调的作用。
如果想了解跟多系统是如何判断是这些手势的可以查看其源码,也可以看下ListView,Gallery的源码前者是在AbsListView中如何判断Tap、Scroll、Fling手势,后者使用的和本文一样,也可以查看其源码更详细的了解当前辅助类的用法。
private class DefaultGestureListener extends SimpleOnGestureListener {// Touch down时触发@Overridepublic boolean onDown(MotionEvent e) {updateLog("onDown");return super.onDown(e);}// 在Touch down之后一定时间(115ms)触发@Overridepublic void onShowPress(MotionEvent e) {updateLog("onShowPress");}@Overridepublic boolean onSingleTapUp(MotionEvent e) {updateLog("onSingleTapUp");return super.onSingleTapUp(e);}// 滑动时触发@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY) {updateLog("onScroll");return super.onScroll(e1, e2, distanceX, distanceY);}// 滑动一段距离,up时触发@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) {updateLog("onFling");return super.onFling(e1, e2, velocityX, velocityY);}// 长按后触发(Touch down之后一定时间(500ms))@Overridepublic void onLongPress(MotionEvent e) {updateLog("onLongPress");}}
创建与触发手势
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mOutput = (TextView) findViewById(R.id.output); output(""); mGestureDetector = new GestureDetector(this, new DefaultGestureListener()); }@Overridepublic boolean onTouchEvent(MotionEvent event) {// 按下时清理之前的记录if (event.getAction() == MotionEvent.ACTION_DOWN) {mRecordMap.clear();}return mGestureDetector.onTouchEvent(event);}
上完整代码
package loveworld.gesturedetector;import java.util.LinkedHashMap;import java.util.Map;import android.app.Activity;import android.os.Bundle;import android.text.TextUtils;import android.util.Log;import android.view.GestureDetector;import android.view.GestureDetector.SimpleOnGestureListener;import android.view.MotionEvent;import android.widget.TextView;/** * * 手势识别 * * * 步骤 * 1. 继承自SimpleOnGestureListener创建子类 * 2. 覆写相应的方法,包括长按,滑动之类的 * * 3. Activity中创建 GestureDetector, 传入自定义子类实例mGestureDetector * 4. Activity覆写onTouchEvent并返回mGestureDetector.onTouchEvent(event); * */public class GestureDetectorDemoActivity extends Activity {// ===========================================================// Constants// ===========================================================// ===========================================================// Fields// ===========================================================private TextView mOutput;private GestureDetector mGestureDetector;private LinkedHashMap<String, Integer> mRecordMap = new LinkedHashMap<String, Integer>();// ===========================================================// Constructors// ===========================================================// ===========================================================// Public Methods// ===========================================================// ===========================================================// Methods for/from SuperClass/Interfaces// ===========================================================@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mOutput = (TextView) findViewById(R.id.output); output(""); mGestureDetector = new GestureDetector(this, new DefaultGestureListener()); }@Overridepublic boolean onTouchEvent(MotionEvent event) {// 按下时清理之前的记录if (event.getAction() == MotionEvent.ACTION_DOWN) {mRecordMap.clear();}return mGestureDetector.onTouchEvent(event);}// ===========================================================// Private Methods// ===========================================================private void updateLog(String name) {if (TextUtils.isEmpty(name)) {return;}if (mRecordMap == null) {Log.e("Test", "mRecordMap == null");}// 不存在创建新的boolean containsKey = mRecordMap.containsKey(name);if (!containsKey) {mRecordMap.put(name, 0);}// 获取之前记录int oldCount = mRecordMap.get( name );int count = oldCount + 1;// 更新记录mRecordMap.put(name, count);// 拼接出来StringBuilder stringBuilder = new StringBuilder();for (Map.Entry<String, Integer> entry : mRecordMap.entrySet()) {String key = entry.getKey();Integer value = entry.getValue();stringBuilder.append("执行方法 : " + key);stringBuilder.append(" , 执行次数 : " + value);stringBuilder.append("\n");}output( stringBuilder.toString() );}private void output(String output) {mOutput.setText("手指在屏幕滑动:\n" + output);}// ===========================================================// Inner and Anonymous Classes// ===========================================================private class DefaultGestureListener extends SimpleOnGestureListener {// Touch down时触发@Overridepublic boolean onDown(MotionEvent e) {updateLog("onDown");return super.onDown(e);}// 在Touch down之后一定时间(115ms)触发@Overridepublic void onShowPress(MotionEvent e) {updateLog("onShowPress");}@Overridepublic boolean onSingleTapUp(MotionEvent e) {updateLog("onSingleTapUp");return super.onSingleTapUp(e);}// 滑动时触发@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY) {updateLog("onScroll");return super.onScroll(e1, e2, distanceX, distanceY);}// 滑动一段距离,up时触发@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) {updateLog("onFling");return super.onFling(e1, e2, velocityX, velocityY);}// 长按后触发(Touch down之后一定时间(500ms))@Overridepublic void onLongPress(MotionEvent e) {updateLog("onLongPress");}}}
布局layout.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/output" android:layout_width="fill_parent" android:layout_height="wrap_content" /></LinearLayout>
三、另外一种使用方式
自定义类继承自SimpleOnGestureListener且实现OnTouchListener,在自定义视图创建的时候创建此自定义类且setOnTouchListener( 当前自定义类对象 )。
那自自定义类与当前自定义视图onTouchEvent的调用顺序?
setOnTouchListener 与 onTouchEvent覆写方法 关系 - setOnTouchListener 是在当前视图的dispatchTouchEvent 中调用
四、可能遇到的问题
如果onScroll、onFling不执行可以尝试覆写onDown返回true
2013-04-18 完全重写本篇文章
2013-05-27 添加可能遇到的问题
2013-02-04 整理到Android事件系列中
一、 效果图
二、代码
在Android中自定义控件通常都会涉及到触摸手势,需要判断用户是点击、滑动、Fling、按下等状态,当前这些都可以通过自己在onTouchEvent中通过MotionEvent回调参数判断得到,但是也可以使用Android系统提供的辅助类SimpleOnGestureListener,以下是继承自此类,主要目的是为了观察各个回调的作用。
如果想了解跟多系统是如何判断是这些手势的可以查看其源码,也可以看下ListView,Gallery的源码前者是在AbsListView中如何判断Tap、Scroll、Fling手势,后者使用的和本文一样,也可以查看其源码更详细的了解当前辅助类的用法。
private class DefaultGestureListener extends SimpleOnGestureListener {// Touch down时触发@Overridepublic boolean onDown(MotionEvent e) {updateLog("onDown");return super.onDown(e);}// 在Touch down之后一定时间(115ms)触发@Overridepublic void onShowPress(MotionEvent e) {updateLog("onShowPress");}@Overridepublic boolean onSingleTapUp(MotionEvent e) {updateLog("onSingleTapUp");return super.onSingleTapUp(e);}// 滑动时触发@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY) {updateLog("onScroll");return super.onScroll(e1, e2, distanceX, distanceY);}// 滑动一段距离,up时触发@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) {updateLog("onFling");return super.onFling(e1, e2, velocityX, velocityY);}// 长按后触发(Touch down之后一定时间(500ms))@Overridepublic void onLongPress(MotionEvent e) {updateLog("onLongPress");}}
创建与触发手势
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mOutput = (TextView) findViewById(R.id.output); output(""); mGestureDetector = new GestureDetector(this, new DefaultGestureListener()); }@Overridepublic boolean onTouchEvent(MotionEvent event) {// 按下时清理之前的记录if (event.getAction() == MotionEvent.ACTION_DOWN) {mRecordMap.clear();}return mGestureDetector.onTouchEvent(event);}
上完整代码
package loveworld.gesturedetector;import java.util.LinkedHashMap;import java.util.Map;import android.app.Activity;import android.os.Bundle;import android.text.TextUtils;import android.util.Log;import android.view.GestureDetector;import android.view.GestureDetector.SimpleOnGestureListener;import android.view.MotionEvent;import android.widget.TextView;/** * * 手势识别 * * * 步骤 * 1. 继承自SimpleOnGestureListener创建子类 * 2. 覆写相应的方法,包括长按,滑动之类的 * * 3. Activity中创建 GestureDetector, 传入自定义子类实例mGestureDetector * 4. Activity覆写onTouchEvent并返回mGestureDetector.onTouchEvent(event); * */public class GestureDetectorDemoActivity extends Activity {// ===========================================================// Constants// ===========================================================// ===========================================================// Fields// ===========================================================private TextView mOutput;private GestureDetector mGestureDetector;private LinkedHashMap<String, Integer> mRecordMap = new LinkedHashMap<String, Integer>();// ===========================================================// Constructors// ===========================================================// ===========================================================// Public Methods// ===========================================================// ===========================================================// Methods for/from SuperClass/Interfaces// ===========================================================@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mOutput = (TextView) findViewById(R.id.output); output(""); mGestureDetector = new GestureDetector(this, new DefaultGestureListener()); }@Overridepublic boolean onTouchEvent(MotionEvent event) {// 按下时清理之前的记录if (event.getAction() == MotionEvent.ACTION_DOWN) {mRecordMap.clear();}return mGestureDetector.onTouchEvent(event);}// ===========================================================// Private Methods// ===========================================================private void updateLog(String name) {if (TextUtils.isEmpty(name)) {return;}if (mRecordMap == null) {Log.e("Test", "mRecordMap == null");}// 不存在创建新的boolean containsKey = mRecordMap.containsKey(name);if (!containsKey) {mRecordMap.put(name, 0);}// 获取之前记录int oldCount = mRecordMap.get( name );int count = oldCount + 1;// 更新记录mRecordMap.put(name, count);// 拼接出来StringBuilder stringBuilder = new StringBuilder();for (Map.Entry<String, Integer> entry : mRecordMap.entrySet()) {String key = entry.getKey();Integer value = entry.getValue();stringBuilder.append("执行方法 : " + key);stringBuilder.append(" , 执行次数 : " + value);stringBuilder.append("\n");}output( stringBuilder.toString() );}private void output(String output) {mOutput.setText("手指在屏幕滑动:\n" + output);}// ===========================================================// Inner and Anonymous Classes// ===========================================================private class DefaultGestureListener extends SimpleOnGestureListener {// Touch down时触发@Overridepublic boolean onDown(MotionEvent e) {updateLog("onDown");return super.onDown(e);}// 在Touch down之后一定时间(115ms)触发@Overridepublic void onShowPress(MotionEvent e) {updateLog("onShowPress");}@Overridepublic boolean onSingleTapUp(MotionEvent e) {updateLog("onSingleTapUp");return super.onSingleTapUp(e);}// 滑动时触发@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY) {updateLog("onScroll");return super.onScroll(e1, e2, distanceX, distanceY);}// 滑动一段距离,up时触发@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) {updateLog("onFling");return super.onFling(e1, e2, velocityX, velocityY);}// 长按后触发(Touch down之后一定时间(500ms))@Overridepublic void onLongPress(MotionEvent e) {updateLog("onLongPress");}}}
二 布局layout.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/output" android:layout_width="fill_parent" android:layout_height="wrap_content" /></LinearLayout>
三、另外一种使用方式
自定义类继承自SimpleOnGestureListener且实现OnTouchListener,在自定义视图创建的时候创建此自定义类且setOnTouchListener( 当前自定义类对象 )。
那自自定义类与当前自定义视图onTouchEvent的调用顺序?
setOnTouchListener 与 onTouchEvent覆写方法 关系 - setOnTouchListener 是在当前视图的dispatchTouchEvent 中调用
四、可能遇到的问题
如果onScroll、onFling不执行可以尝试覆写onDown返回true
2013-04-18 完全重写本篇文章
2013-05-27 添加可能遇到的问题
2014-02-04 添加到事件学习系列中
- 第19天 Android Touch事件学习 6 手势识别
- 第16天 Android Touch事件学习 3 区分各种手势基础知识
- 第14天 Android Touch事件学习 1 点击事件
- Android的Touch事件处理和手势
- 手势识别与事件库 Touch.js若干问题及解决方法
- 第15天 Android Touch事件学习 2 触发点击事件的地方
- 第20天 Android Touch事件学习 7 交给哪个视图处理事件?
- 第21天 Android Touch事件学习 8 事件分发原理
- 学习笔记 - 触摸事件&手势识别
- 第17天 Android Touch事件学习 4 获取手指触摸位置
- 第18天 Android Touch事件学习 5 点击与长按原理
- Android手势识别和双击事件
- 2014-11-8Android学习------手势识别事件的处理GestureDetector--------动画Animation学习篇
- Android基础之Touch事件和手势处理
- 手势识别事件详解
- Android 触屏事件处理_手势识别 鼠标事件
- iOS个人整理08-touch触摸事件和手势识别器
- Android GestureDetector手势识别类学习
- 4.4 Activity的重建
- 总结一下国内著名的计算机图书出版机构(2014年4月)
- Codeforces Beta Round #2 A B C
- Python系列视频教程: Django【13讲】第十讲 数据库管理
- 改变UITabBarController选中的View Controller
- 第19天 Android Touch事件学习 6 手势识别
- fl2440的内核移植总结
- 2014年技术规划
- windows下为eclipse配置pydev
- C++基础细节2
- iOS平台的应用程序调试与分析
- 返回指定长度的随机数(在前面补0)
- Jackson 框架 用例详解
- Qt对象模型和容器类