Android学习 - 触摸及手势操作

来源:互联网 发布:js让隐藏的div显示 编辑:程序博客网 时间:2024/05/18 22:53

GestureDetector简介

触摸屏为我们操作无键盘、无鼠标的手机系统带来了很多的便利。当用户触摸屏幕时会产生很多的触摸事件,down、up、move等等。View类有个View.OnTouchListener内部接口,通过重写他的onTouch(View v, MotionEvent event)方法,我们可以处理一些touch事件,如下:

public class MainActivity extends Activity {……// This example shows an Activity, but you would use the same approach if// you were subclassing a View.@Overridepublic boolean onTouchEvent(MotionEvent event) {int action = MotionEventCompat.getActionMasked(event);switch (action) {case (MotionEvent.ACTION_DOWN):Log.d(DEBUG_TAG, "Action was DOWN");return true;case (MotionEvent.ACTION_MOVE):Log.d(DEBUG_TAG, "Action was MOVE");return true;case (MotionEvent.ACTION_UP):Log.d(DEBUG_TAG, "Action was UP");return true;case (MotionEvent.ACTION_CANCEL):Log.d(DEBUG_TAG, "Action was CANCEL");return true;case (MotionEvent.ACTION_OUTSIDE):Log.d(DEBUG_TAG, "Movement occurred outside bounds "+ "of current screen element");return true;default:return super.onTouchEvent(event);}}}

OnTouch提供的事件还是相对较简单,如果需要处理一些复杂的手势,用这个接口就会很麻烦,因为我们要根据用户触摸的轨迹去判断是什么手势。Android sdk给我们提供了GestureDetector(Gesture:手势Detector:识别)类,通过这个类我们可以识别很多的手势。

public class GestureDetector extends Objectjava.lang.Objectandroid.view.GestureDetector

GestureDetector属于android.view包,android还提供了android.gesture包支持更多的手势操作,以后我们会介绍到。官方的介绍中使用了GestureDetectorCompat处理手势识别,为什么使用GestureDetectorCompat替换了GestureDetector呢,官方的是这样解释的:

Detects various gestures and eventsusing the supplied MotionEventS. The GestureDetector.OnGestureListenercallback willnotify users when a particular motion event has occrurred. This class shouldonly be used withMotionEventS reported viatouch (don’t use for trackball events).

This compatibility implementation fo theframework’s GestureDetector guarantees the newer focal point scrolling behaviorfrom Jellybean MRI on all platform versions.

GestureDetectorCompat实例化有下面两种方法:

GestureDetectorCompat(Context context, GestureDetector.OnGestureListener listener)GestureDetectorCompat(Context context, GestureDetector.OnGestureListener listener, Handler handler)

GestureDetector类对外提供了两个接口:OnGestureListener、OnDoubleTapListener还有一个内部类SimpleOnGestureListener;SimpleOnGestureListener类是GestureDetector提供给我们的一个更方便的响应不同手势的类,它实现了上述两个接口,该类是staticclass,也就是说它实际上是一个外部类,我们可以在外部继承这个类,重写里面的手势处理方法。因此实现手势识别有两种方法,一种实现OnGestureListener接口,另一种是使用SimpleOnGestureListener类。

OnGestureListener有下面的几个动作:

按下(onDown):刚刚手指接触到触摸屏的那一刹那,就是触的那一下。

抛掷(onFling):手指在触摸屏上迅速移动,并松开的动作。

长按(onLongPress):手指按在持续一段时间,并且没有松开。

滚动(onScroll):手指在触摸屏上滑动。

按住(onShowPress):手指按在触摸屏上,它的时间范围在按下起效,在长按之前。

抬起(onSingleTapUp):手指离开触摸屏的那一刹那。

使用OnGestureListener接口,这样需要重载OnGestureListener接口所有的方法,适合监听所有的手势,正如官方文档提到的“DetecingAll Supported Gestures”。

public class MainActivity extends Activity implementsGestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {private static final String DEBUG_TAG = "Gestures";private GestureDetectorCompat mDetector;// Called when the activity is first created.@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// Instantiate the gesture detector with the// application context and an implementation of// GestureDetector.OnGestureListenermDetector = new GestureDetectorCompat(this, this);// Set the gesture detector as the double tap// listener.mDetector.setOnDoubleTapListener(this);}@Overridepublic boolean onTouchEvent(MotionEvent event) {this.mDetector.onTouchEvent(event);// Be sure to call the superclass implementationreturn super.onTouchEvent(event);}@Overridepublic boolean onDown(MotionEvent event) {Log.d(DEBUG_TAG, "onDown: " + event.toString());return true;}@Overridepublic boolean onFling(MotionEvent event1, MotionEvent event2,float velocityX, float velocityY) {Log.d(DEBUG_TAG, "onFling: " + event1.toString() + event2.toString());return true;}@Overridepublic void onLongPress(MotionEvent event) {Log.d(DEBUG_TAG, "onLongPress: " + event.toString());}@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,float distanceY) {Log.d(DEBUG_TAG, "onScroll: " + e1.toString() + e2.toString());return true;}@Overridepublic void onShowPress(MotionEvent event) {Log.d(DEBUG_TAG, "onShowPress: " + event.toString());}@Overridepublic boolean onSingleTapUp(MotionEvent event) {Log.d(DEBUG_TAG, "onSingleTapUp: " + event.toString());return true;}@Overridepublic boolean onDoubleTap(MotionEvent event) {Log.d(DEBUG_TAG, "onDoubleTap: " + event.toString());return true;}@Overridepublic boolean onDoubleTapEvent(MotionEvent event) {Log.d(DEBUG_TAG, "onDoubleTapEvent: " + event.toString());return true;}@Overridepublic boolean onSingleTapConfirmed(MotionEvent event) {Log.d(DEBUG_TAG, "onSingleTapConfirmed: " + event.toString());return true;}}

这样会造成有些手势动作我们用不到,但是还要重载。SimpleOnGestureListener类的出现为我们解决了这个问题,如果你想“Detecting a Subset of Supported Gestures”,SimpleOnGestureListener是最好的选择。

public class MainActivity extends Activity {private GestureDetectorCompat mDetector;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mDetector = new GestureDetectorCompat(this, new MyGestureListener());}@Overridepublic boolean onTouchEvent(MotionEvent event) {this.mDetector.onTouchEvent(event);return super.onTouchEvent(event);}class MyGestureListener extends GestureDetector.SimpleOnGestureListener {private static final String DEBUG_TAG = "Gestures";@Overridepublic boolean onDown(MotionEvent event) {Log.d(DEBUG_TAG, "onDown: " + event.toString());return true;}@Overridepublic boolean onFling(MotionEvent event1, MotionEvent event2,float velocityX, float velocityY) {Log.d(DEBUG_TAG,"onFling: " + event1.toString() + event2.toString());return true;}}}

最后了我们也解释两个问题:

1、onTouchEvent中为什么使用了MotionEventCompat,而不直接使用MotionEvent。因为MotionEventCompat使更多的Action适配到API 4。

2、Android的view怎么使用手势,方法如下:

View myView = findViewById(R.id.my_view);myView.setOnTouchListener(new OnTouchListener() {    public boolean onTouch(View v, MotionEvent event) {        // ... Respond to touch events        this.mDetector.onTouchEvent(event);        return super.onTouchEvent(event);    }});

android源码gesture.builder.rar:http://pan.baidu.com/s/1c0k3OlE

android手势创建及识别

使用一些浏览器或者输入法应用时会有一些手势操作,还可以自定义手势。这些神奇的操作是怎么做的呢?这一篇重点记录手势的识别和创建。这篇的内容使用到的是android.gesture包,具体的例子参考的是Sample中GestureBuilder程序。

1、手势创建

手势创建主要用到GestureOverlayView和GestureLibrary。GestureOverlayView的父类为android.widget.FrameLayout,是手势绘图区。GestureLibrary类主要对手势进行保存、删除等操作的,存放手势的仓库。下面给出创建手势的例子,如下图,可以定义如图手势打开。


1.1、创建绘图区

GestureOverlayView overlay = (GestureOverlayView) findViewById(R.id.gestures_overlay);overlay.setGestureStrokeType(GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE);overlay.setFadeOffset(2000); // 多笔画每两次的间隔时间overlay.setGestureColor(Color.CYAN);// 画笔颜色overlay.setGestureStrokeWidth(6);// 画笔粗细值overlay.addOnGestureListener(new GesturesProcessor());

1.2、监听绘制

private class GesturesProcessor implementsGestureOverlayView.OnGestureListener {public void onGestureStarted(GestureOverlayView overlay,MotionEvent event) {mDoneButton.setEnabled(false);mGesture = null;}public void onGesture(GestureOverlayView overlay, MotionEvent event) {}public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) {mGesture = overlay.getGesture();if (mGesture.getLength() < LENGTH_THRESHOLD) {overlay.clear(false);}mDoneButton.setEnabled(true);}public void onGestureCancelled(GestureOverlayView overlay,MotionEvent event) {}}

1.3、保存手势

public void addGesture(View v) {if (mGesture != null) {final TextView input = (TextView) findViewById(R.id.gesture_name);final CharSequence name = input.getText();if (name.length() == 0) {input.setError(getString(R.string.error_missing_name));return;}/** * 获取手势库 private final File mStoreFile = new * File(Environment.getExternalStorageDirectory(), "gestures"); * GestureLibrary sStore = GestureLibraries.fromFile(mStoreFile); *  */final GestureLibrary store = GestureBuilderActivity.getStore();store.addGesture(name.toString(), mGesture);store.save();setResult(RESULT_OK);final String path = new File(Environment.getExternalStorageDirectory(), "gestures").getAbsolutePath();Toast.makeText(this, getString(R.string.save_success, path),Toast.LENGTH_LONG).show();} else {setResult(RESULT_CANCELED);}finish();}

2、手势识别

手势识别也是经过创建绘图区、监听绘制、比对结果三个过程,这里直接给出代码。

public class GesturePerformedActivity extends Activity {private final File mStoreFile = new File(Environment.getExternalStorageDirectory(), "gestures");// 手势库GestureLibrary mGestureLib;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.gesture_perform);// 手势画板GestureOverlayView gestures = (GestureOverlayView) findViewById(R.id.gestures_overlay);gestures.setGestureStrokeType(GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE);gestures.setFadeOffset(2000); // 多笔画每两次的间隔时间gestures.setGestureColor(Color.CYAN);// 画笔颜色gestures.setGestureStrokeWidth(6);// 画笔粗细值// 手势识别的监听器gestures.addOnGesturePerformedListener(new GestureOverlayView.OnGesturePerformedListener() {@Overridepublic void onGesturePerformed(GestureOverlayView overlay,Gesture gesture) {// 从手势库中查询匹配的内容,匹配的结果可能包括多个相似的结果,匹配度高的结果放在最前面ArrayList<Prediction> predictions = mGestureLib.recognize(gesture);if (predictions.size() > 0) {Prediction prediction = (Prediction) predictions.get(0);// 匹配的手势if (prediction.score > 1.0) { // 越匹配score的值越大,最大为10Toast.makeText(GesturePerformedActivity.this,prediction.name, Toast.LENGTH_SHORT).show();}}}});if (mGestureLib == null) {mGestureLib = GestureLibraries.fromFile(mStoreFile);mGestureLib.load();}}}




最后还有点问题,就是多笔画识别问题,这里没有很好的解决,使用OnGesturePerformedListener接听结束,有的多笔画会识别失败,尤其简单的横线竖线组合,复杂的却没有问题。如果使用GestureOverlayView.OnGestureListener监听结束,每一笔画都会调用,不能处理未知笔画数的识别。

android源码gesture.builder.rar:http://pan.baidu.com/s/1c0k3OlE

0 0