本系列文章均為A2BGeek原創(chuàng),轉(zhuǎn)載務(wù)必在明顯處注明:
轉(zhuǎn)載自A2BGeek的【Android每周專題】系列,原文鏈接:
http://blog.csdn.net/benbmw2008/article/details/11367631
這篇專題來(lái)研究一下Android的觸摸屏手勢(shì)Gesture,Android的手勢(shì)有兩種,一種是View和Activity的(基于觸摸屏事件,所以Activity也能添加手勢(shì)),一種是手寫輸入法或者一些手機(jī)瀏覽器的快捷手勢(shì)那樣的帶筆跡的手勢(shì)識(shí)別。這一點(diǎn)從API文檔中就能體現(xiàn)出來(lái):分別有android.view.GestureDetector和android.gesture.Gesture。
我們先來(lái)介紹View和Activity的手勢(shì),再介紹輸入法手勢(shì)識(shí)別。
View和Activity的手勢(shì)
拋擲(onFling): 手指在觸摸屏上迅速移動(dòng),并松開的動(dòng)作。
長(zhǎng)按(onLongPress): 手指按在持續(xù)一段時(shí)間,并且沒有松開。
滾動(dòng)(onScroll): 手指在觸摸屏上滑動(dòng)。
按住(onShowPress): 手指按在觸摸屏上,它的時(shí)間范圍在按下起效,在長(zhǎng)按之前。
抬起(onSingleTapUp):手指離開觸摸屏的那一剎那。
除了這些定義之外,鄙人也總結(jié)了一點(diǎn)算是經(jīng)驗(yàn)的經(jīng)驗(yàn)吧,在這里和大家分享一下。
任何手勢(shì)動(dòng)作都會(huì)先執(zhí)行一次按下(onDown)動(dòng)作。
長(zhǎng)按(onLongPress)動(dòng)作前一定會(huì)執(zhí)行一次按?。╫nShowPress)動(dòng)作。
按?。╫nShowPress)動(dòng)作和按下(onDown)動(dòng)作之后都會(huì)執(zhí)行一次抬起(onSingleTapUp)動(dòng)作。
長(zhǎng)按(onLongPress)、滾動(dòng)(onScroll)和拋擲(onFling)動(dòng)作之后都不會(huì)執(zhí)行抬起(onSingleTapUp)動(dòng)作。
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的帶返回值的幾個(gè)回調(diào)方法默認(rèn)返回false的情況下,你會(huì)發(fā)現(xiàn)Fling手勢(shì)是識(shí)別不到的,這是什么原因呢?這需要用上一專題的知識(shí)來(lái)解釋 http://blog.csdn.net/benbmw2008/article/details/11143893 。 大家應(yīng)該能看出來(lái)手勢(shì)是基于觸摸屏事件傳遞的,對(duì)照著上一篇的“默認(rèn)事件流向”圖,讀者可以想象其實(shí)就是在“MyTextView onTouchEvent”和“MyRelativeLayout onTouchEvent”之間加一個(gè)"MyTextView's GestureDetector onTouchEvent",而"MyTextView's GestureDetector onTouchEvent"返回false,事件還是會(huì)繼續(xù)傳遞給“MyRelativeLayout onTouchEvent”。 解決的辦法是什么呢?自然是把OnGestureListener的帶返回值的幾個(gè)回調(diào)方法返回true,這樣觸摸屏事件就被“GestureDetector onTouchEvent”所消費(fèi),看一下日志會(huì)更加清楚:
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
輸入法手勢(shì)識(shí)別
<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匹配的手勢(shì)集,匹配的程度會(huì)有一個(gè)score評(píng)分。
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();
}
}
}
}
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元

