国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android手勢識別功能

2019-12-12 03:56:15
字體:
來源:轉載
供稿:網友

現在智能手機基本都是觸摸操作,點擊按鈕是一種交互方式,同時手勢相關的操作,比如滑動等等同樣是很重要的交互方式。這篇文章是對安卓手勢交互相關知識點的整理和總結,主要來源基于官方文檔。

觸摸交互中的概念

常用事件

首先要了解一些常用的事件:
ACTION_DOWN:第一個手指按下
ACTION_UP:第一個手指抬起
ACTION_POINTER_DOWN:第二、三、四等等手指按下
ACTION_POINTER_UP: 第二、三、四等等手指抬起
ACTION_MOVE: 手指移動
ACTION_OUTSIDE:手指移出了屏幕
ACTION_CANCEL:收到前驅事件比如ACTION_DOWN后,后續事件被父控件攔截的情況下產生

上面我們可以看到,除了第一個手指有唯一的action down和action up事件觸發,后續其它手指的按下和移動,都觸發的是同一個事件。那么這個時候就可能涉及到對不同手指區分的邏輯處理。

MotionEvent

MotionEvent中用action code和坐標值描述了觸摸運動的軌跡,action code值描述了運動狀態的改變,坐標值描述了軌跡的位置和一起其它信息。
比如 ACTION_DOWN表明手指開始觸碰到屏幕,X和Y的坐標軸值表明了當前的位置。

上面僅僅是基本的單指操作,但是現在很多設備都提供多指操作的功能。多個手指每個手指都被在第一次觸碰屏幕的時候分配一個pointer id,直到這個手指離開相應的pointer id才變無效。當第一個手指按下時,會觸發ACTION_DOWN,ACTION_MOVE一系列的事件,同時當第二個手指按下的時候,又會觸發 ACTION_POINTER_DOWN事件,此后兩個手指移動的時候,只會觸發ACTION_MOVE事件。當一個ACTION_MOVE觸發的時,通過使用 getPointerId(第幾個手指) 方法去獲取pointer id明確是哪一個手指,然后使用使用findPointerIndex 方法去獲得pointer index,pointer index代表了這一個MotionEvent事件中哪一個是當前pointer對應的事件。

MotionEvent事件捆綁

結合上面的概念,再來說一下MotionEvent的捆綁。為了處理效率,安卓中會把MOVE動作中多個坐標點捆綁在一個MotionEvent中,對于單個手指操作,getX返回的是最近一點的坐標,getHistoricalX 返回的是之前的坐標。看下面一段代碼:

 void printSamples(MotionEvent ev) {   //獲取MotionEvent中捆綁的坐標點   final int historySize = ev.getHistorySize();   //獲取手指數目   final int pointerCount = ev.getPointerCount();   for (int h = 0; h < historySize; h++) {     System.out.printf("At time %d:", ev.getHistoricalEventTime(h));     for (int p = 0; p < pointerCount; p++) {       System.out.printf(" pointer %d: (%f,%f)",         ev.getPointerId(p), ev.getHistoricalX(p, h), ev.getHistoricalY(p, h));     }   } }

可以看到,一個MotionEvent中,可能包括多個手指的動作信息,以及一些歷史信息。

事件分發機制

MotionEvent代表觸摸后響應的事件,安卓中的視圖是按照視圖樹構建而成的,點擊之后,會生成點擊事件MotionEvent并沿樹傳遞。

與事件分發有關的方法有:
public boolean dispatchTouchEvent(MotionEvent ev) 事件分發
public boolean onInterceptTouchEvent(MotionEvent ev) 事件攔截
public boolean onTouchEvent(MotionEvent ev) 事件響應

在一個ViewGroup中通常會具有以上三個方法,可以進行事件的分發、攔截和響應,而在一個View中因為沒有子View,所以只能進行事件的處理,也就只有onTouchEvent方法。

dispatchTouchEvent

事件分發的過程中,會以深度遍歷的方式進行分發。分以下情況:

返回true,則事件會分發給當前View,由當前View消費。
返回false,將事件返回給父View進行消費
默認 super.dispatchTouchEvent(ev),會調用當前View的 onInterceptTouchEvent 進行攔截處理。
一般情況下,我們不會去重寫view的分發過程,而是著重處理事件的攔截和響應。

onInterceptTouchEvent

如果返回true,則攔截當前事件,交由onTouchEvent處理
如果返回false,則不攔截當前事件,交由子View的dispatchTouchEvent處理
如果調用默認 super.onInterceptTouchEvent,則攔截當前事件。

onTouchEvent

如果返回false,表明當前View無法處理,之間會返回上級有上級View的onTouchEvent處理,一直 向上傳遞直到事件被消費。
如果返回true則會接收并消費該事件
如果返回 super.onTouchEvent(ev) 默認處理事件的邏輯和返回 false 時相同。
注意,對于View而非ViewGroup來說,只具有onTouchEvent方法。所以在一個View中,處理事件響應的典型代碼如下:

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 :    //當前View不處理事件,交由上層處理。      return super.onTouchEvent(event);  }}

同樣,一個View處理觸摸事件,還可以設置監聽器onTouchListener,不過要注意的是onTouchListener的優先級比onTouch要高,如果其中返回了true,那么將不會調用onTouch方法。

手勢探測

onTouch中我們可以通過MotionEvent獲取觸摸點的坐標信息,但是關于某些手勢比如點擊、滑動還需要進行我們自己的邏輯處理。在這里Android本身提供了一些手勢判別的功能。這樣在onTouch方法中,我們只需要把MotionEvent傳遞給手勢監聽器處理即可,同時實現接口中相應的回調方法:

private GestureDetectorCompat mDetector;  public void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    mDetector = new GestureDetectorCompat(this,this);    mDetector.setOnDoubleTapListener(this);  }  @Override  public boolean onTouchEvent(MotionEvent event){    this.mDetector.onTouchEvent(event);    // Be sure to call the superclass implementation    return super.onTouchEvent(event);  }

如果不需要監聽那么多事件,那么可以寫一個監聽類繼承GestureDetector.SimpleOnGestureListener并實現其中的方法。

如果要監聽觸摸的速度,那么可以通過VelocityTracker來監聽:

    switch(action) {      case MotionEvent.ACTION_DOWN:        if(mVelocityTracker == null) {                   mVelocityTracker = VelocityTracker.obtain();        }        else {          mVelocityTracker.clear();        }        mVelocityTracker.addMovement(event);        break;      case MotionEvent.ACTION_MOVE:        mVelocityTracker.addMovement(event);        mVelocityTracker.computeCurrentVelocity(1000);        Log.d("", "X velocity: " +            VelocityTrackerCompat.getXVelocity(mVelocityTracker,            pointerId));        Log.d("", "Y velocity: " +            VelocityTrackerCompat.getYVelocity(mVelocityTracker,            pointerId));        break;      case MotionEvent.ACTION_UP:      case MotionEvent.ACTION_CANCEL:        mVelocityTracker.recycle();        break;

通過將MotionEvent加入VelocityTracker中,可以通過computeCurrentVelocity算出速度。
(未完待續。。。)

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 和林格尔县| 时尚| 墨竹工卡县| 罗江县| 乡宁县| 陈巴尔虎旗| 张北县| 泾川县| 于都县| 常熟市| 阜阳市| 崇礼县| 永吉县| 高安市| 电白县| 建昌县| 合水县| 阜平县| 西城区| 崇信县| 安化县| 汶川县| 宜春市| 水富县| 公主岭市| 石景山区| 罗平县| 鄂温| 突泉县| 星座| 安泽县| 佳木斯市| 广昌县| 双流县| 瑞丽市| 阜城县| 滕州市| 白沙| 镇赉县| 开封市| 宜宾县|