”触摸手势“发生在用户放置一个或者多个手指在触摸屏上的时候,然后你的应用程序翻译这个触摸模型作为一个特别的手势。手势检测有相应的两个阶段:
采集关于触摸事件的数据。
翻译这个数据去查看它是否符合你的应用程序支持的任何手势的标准。
在这个课程中的例子使用了GestureDetectorCompat和MotionEventCompat类。这些类都在Support Library中。你应该在可能提供兼容性,运行Android1.6和更高的设备中使用支持库类。注意MotionEventCompat不是MotionEvent类的一个替代。当然,它提供了静态实体方法,你传递给你的MotionEvent对象,为了获取和事件相关的期望的动作。
—————————————————————————————————————————————————————————————————
当用户放置一个或者多个手指在屏幕上的时候,触发在获取触摸事件的视图中的onTouchEvent()方法。对于每个序列的触摸事件(position.pressure,size,addition of another finder,ect.)最终确定为一个手势,onTouchEvent()方法被触发几次。
手势从用户第一次触摸屏幕的时候开始,随着系统跟踪用户手指的位置而继续,最后以捕获用户手指离开屏幕的最后事件结束。整个交互中,MotionEvent被分传递给onTouchEvent()方法,提供了每个交互的详细说明。你的应用程序能使用通过MotionEvent提供的数据,来确定一个手势是否发生。
为了截取在Activity或者View中的触摸事件,覆盖onTouchEvent()回调方法。
下面的代码块使用了getActionMasked()方法,从event参数中提取用户执行的动作。它给你提供了用来决定一个手势是否发生的原始数据:
public class MainActivity extends Activity { ... // This example shows an Activity, but you would use the same approach if // you were subclassing a View. @Override public 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); } }你然后在这些事件中能做自己的处理,来确定是否发生了一个手势。对于自定义手势这种处理是你必须做的。然而,如果你的应用程序使用通常的手势,例如双击,长按,点,等等,你可以充分利用GestureDetector类。GestureDetector不处理个人的触摸事件,使检测通常的手势对于你变得简单。这个在下面Detect Gestures中被讨论。
作为onTouchEvent()方法供替代的选择,你能使用setOnTouchListener()方法给任何View附加一个View.onTouchListener对象。这使的监听触摸事件,但没有子类化一个已存在View成为可能。例如:
View myView = findViewById(R.id.my_view); myView.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // ... Respond to touch events return true; } });谨防创建一个对ACTION_DOWN事件返回false的监听器。如果你这样做,这个监听器将不会在接下来的ACTION_MOVE和ACTION_UP字符串事件中被调用。这是因为ACTION_DOWN是所有触摸事件的起点。
如果你创建一个自定义的View,你能覆盖onTouchEvent()方法,如上面所描述的。
Android提供了GestureDetector类来检测普通的手势。它支持的一些手势包括onDown(),onLongPress(),onFling(),等等。你能结合上面描述的onTouchEvent()方法使用GestureDetector类。
当你实例化一个GestureDectectorCompat对象的时候,它使用的一个参数是一个实现了GestureDectector.onGestureListener接口的类。当一个特定的触摸事件发生的时候,GestureDetector.onGestureListener通知用户。为了使你的GestureDetector对象获取这个事件变成可能,你覆盖这个View或者Activity的onTouchEvent()方法,并传递所可被观察到的事件给这个检测者实例。
在下面的代码块中,从各个on<TouchEvenet>方法返回一个true值,说明了你已经处理了这个事件。一个false返回值传递事件到这个View栈,直到这个触摸已经被成功的处理。
运行下面的代码块,感受一下当你和触摸屏交互的时候,操作是如何被触发的,和每个触摸事件的MetionEventneo内容。你将会认识到简单的交互生成了如此多的数据。
public class MainActivity extends Activity implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener{ private static final String DEBUG_TAG = "Gestures"; private GestureDetectorCompat mDetector; // Called when the activity is first created. @Override public 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.OnGestureListener mDetector = new GestureDetectorCompat(this,this); // Set the gesture detector as the double tap // listener. mDetector.setOnDoubleTapListener(this); } @Override public boolean onTouchEvent(MotionEvent event){ this.mDetector.onTouchEvent(event); // Be sure to call the superclass implementation return super.onTouchEvent(event); } @Override public boolean onDown(MotionEvent event) { Log.d(DEBUG_TAG,"onDown: " + event.toString()); return true; } @Override public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { Log.d(DEBUG_TAG, "onFling: " + event1.toString()+event2.toString()); return true; } @Override public void onLongPress(MotionEvent event) { Log.d(DEBUG_TAG, "onLongPress: " + event.toString()); } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { Log.d(DEBUG_TAG, "onScroll: " + e1.toString()+e2.toString()); return true; } @Override public void onShowPress(MotionEvent event) { Log.d(DEBUG_TAG, "onShowPress: " + event.toString()); } @Override public boolean onSingleTapUp(MotionEvent event) { Log.d(DEBUG_TAG, "onSingleTapUp: " + event.toString()); return true; } @Override public boolean onDoubleTap(MotionEvent event) { Log.d(DEBUG_TAG, "onDoubleTap: " + event.toString()); return true; } @Override public boolean onDoubleTapEvent(MotionEvent event) { Log.d(DEBUG_TAG, "onDoubleTapEvent: " + event.toString()); return true; } @Override public boolean onSingleTapConfirmed(MotionEvent event) { Log.d(DEBUG_TAG, "onSingleTapConfirmed: " + event.toString()); return true; } }
如果你仅仅想处理一些手势,你能继承GestureDetector.SimpleOnGestureListener替代实现GestureDectector.onGestureListener接口。
GestureDetector.SimpleOnGestureListener提供了所有on<TouchEvent>方法的一个实现,所有返回false。因此你能仅仅覆盖你关心的方法。例如,下面的代码块创建了一个类,它继承了GestureDectedtor.SimpleonGestureListener,并且覆盖了onFling()和onDown()方法。
不论你是否使用GestureDectector.onGestureListener,实现一个onDown()方法的最好实践是返回ture。这个是因为所有的手势都是以onDown()消息开始的。如果你从onDown()方法返回false,如GestureDectector.SimpleOnGestureListener默认行为,这个系统假设你不会理睬其余的手势,并且其它GestureDectector.onGestureListener的方法从来不会调用。这可能在你的应用程序中导致意外的问题。你能从onDown()方法返回false的唯一时间是,如果你真的想不理睬整个手势。
public class MainActivity extends Activity { private GestureDetectorCompat mDetector; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mDetector = new GestureDetectorCompat(this, new MyGestureListener()); } @Override public boolean onTouchEvent(MotionEvent event){ this.mDetector.onTouchEvent(event); return super.onTouchEvent(event); } class MyGestureListener extends GestureDetector.SimpleOnGestureListener { private static final String DEBUG_TAG = "Gestures"; @Override public boolean onDown(MotionEvent event) { Log.d(DEBUG_TAG,"onDown: " + event.toString()); return true; } @Override public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { Log.d(DEBUG_TAG, "onFling: " + event1.toString()+event2.toString()); return true; } } }