Android手勢(shì)監(jiān)聽類GestureDetector

一棘利、概述
當(dāng)用戶觸摸屏幕的時(shí)候,會(huì)產(chǎn)生許多手勢(shì)朽缴,例如down,up水援,scroll密强,filing等等。一般情況下蜗元,我們知道View類有個(gè)View.OnTouchListener內(nèi)部接口或渤,通過重寫他的onTouch(View v, MotionEvent event)方法,我們可以處理一些touch事件奕扣,但是這個(gè)方法太過簡(jiǎn)單薪鹦,如果需要處理一些復(fù)雜的手勢(shì),用這個(gè)接口就會(huì)很麻煩(因?yàn)槲覀円约焊鶕?jù)用戶觸摸的軌跡去判斷是什么手勢(shì))。Android sdk給我們提供了GestureDetector(Gesture:手勢(shì)Detector:識(shí)別)類池磁,通過這個(gè)類我們可以識(shí)別很多的手勢(shì)奔害,主要是通過他的onTouchEvent(event)方法完成了不同手勢(shì)的識(shí)別。雖然他能識(shí)別手勢(shì)地熄,但是不同的手勢(shì)要怎么處理华临,應(yīng)該是提供給程序員實(shí)現(xiàn)的。

首先介紹一下觸屏事件處理的基本思路端考。觸屏一般有三個(gè)基本事件雅潭,down按下,move移動(dòng)却特,up離開扶供,通過對(duì)這三個(gè)基本事件的監(jiān)聽,判斷用戶執(zhí)行了何種操作裂明。一個(gè)標(biāo)準(zhǔn)的觸屏操作一般都是一系列基本事件的組合椿浓,在Android的框架中,通過onTouch()函數(shù)可以獲取基本的觸屏事件漾岳,而像onClick這樣的函數(shù)轰绵,已經(jīng)是一系列基本事件的組合。

比如尼荆,發(fā)生了Down事件左腔,在up事件之前沒有發(fā)生move事件,或者move的范圍很小捅儒,并且down事件和up事件的間隔很短液样,這就是一個(gè)click或者singelTap事件,

對(duì)比實(shí)體鍵盤按鍵的事件巧还,實(shí)體鍵盤是在down事件發(fā)生后進(jìn)行操作鞭莽,而觸屏事件一般是up事件發(fā)生后進(jìn)行操作。

GestureDetector這個(gè)類對(duì)外提供了兩個(gè)接口和一個(gè)外部類
接口:OnGestureListener麸祷,OnDoubleTapListener
內(nèi)部類:SimpleOnGestureListener
這個(gè)外部類澎怒,其實(shí)是兩個(gè)接口中所有函數(shù)的集成,它包含了這兩個(gè)接口里所有必須要實(shí)現(xiàn)的函數(shù)而且都已經(jīng)重寫阶牍,但所有方法體都是空的喷面;不同點(diǎn)在于:該類是static class,程序員可以在外部繼承這個(gè)類走孽,重寫里面的手勢(shì)處理方法惧辈。
下面我們先看OnGestureListener接口;
二磕瓷、GestureDetector.OnGestureListener---接口
1盒齿、基本講解
如果我們寫一個(gè)類并implements OnGestureListener念逞,會(huì)提示有幾個(gè)必須重寫的函數(shù),加上之后是這個(gè)樣子的:

private class gesturelistener implements GestureDetector.OnGestureListener{  
  
    public boolean onDown(MotionEvent e) {  
        // TODO Auto-generated method stub  
        return false;  
    }  
  
    public void onShowPress(MotionEvent e) {  
        // TODO Auto-generated method stub  
          
    }  
  
    public boolean onSingleTapUp(MotionEvent e) {  
        // TODO Auto-generated method stub  
        return false;  
    }  
  
    public boolean onScroll(MotionEvent e1, MotionEvent e2,  
            float distanceX, float distanceY) {  
        // TODO Auto-generated method stub  
        return false;  
    }  
  
    public void onLongPress(MotionEvent e) {  
        // TODO Auto-generated method stub  
          
    }  
  
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,  
            float velocityY) {  
        // TODO Auto-generated method stub  
        return false;  
    }  
      
}  ```
可見边翁,這里總共重寫了六個(gè)函數(shù)翎承,這些函數(shù)都在什么情況下才會(huì)觸發(fā)呢,下面講一下:

**OnDown(MotionEvent e):**用戶按下屏幕就會(huì)觸發(fā)倒彰;
**onShowPress(MotionEvent e):**如果是按下的時(shí)間超過瞬間审洞,而且在按下的時(shí)候沒有松開或者是拖動(dòng)的,那么onShowPress就會(huì)執(zhí)行待讳,具體這個(gè)瞬間是多久芒澜,我也不清楚呃……
**onLongPress(MotionEvent e):**長(zhǎng)按觸摸屏,超過一定時(shí)長(zhǎng)创淡,就會(huì)觸發(fā)這個(gè)事件    觸發(fā)順序:    onDown->onShowPress->onLongPress
**onSingleTapUp(MotionEvent e):**從名子也可以看出,一次單獨(dú)的輕擊抬起操作,也就是輕擊一下屏幕痴晦,立刻抬起來,才會(huì)有這個(gè)觸發(fā)琳彩,當(dāng)然,如果除了Down以外還有其它操作,那就不再算是Single操作了,所以也就不會(huì)觸發(fā)這個(gè)事件    
觸發(fā)順序:    
點(diǎn)擊一下非程茏茫快的(不滑動(dòng))Touchup:   
 onDown->onSingleTapUp->onSingleTapConfirmed     
點(diǎn)擊一下稍微慢點(diǎn)的(不滑動(dòng))Touchup:    
onDown->onShowPress->onSingleTapUp->onSingleTapConfirmed
**onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) :**滑屏,用戶按下觸摸屏露乏、快速移動(dòng)后松開碧浊,由1個(gè)MotionEvent ACTION_DOWN, 多個(gè)ACTION_MOVE, 1個(gè)ACTION_UP觸發(fā)        
參數(shù)解釋:    
e1:第1個(gè)ACTION_DOWN MotionEvent    
e2:最后一個(gè)ACTION_MOVE MotionEvent    
velocityX:X軸上的移動(dòng)速度,像素/秒    
velocityY:Y軸上的移動(dòng)速度瘟仿,像素/秒   
**onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY):**在屏幕上拖動(dòng)事件箱锐。無論是用手拖動(dòng)view,或者是以拋的動(dòng)作滾動(dòng)劳较,都會(huì)多次觸發(fā),這個(gè)方法       在ACTION_MOVE動(dòng)作發(fā)生時(shí)就會(huì)觸發(fā)    滑屏:手指觸動(dòng)屏幕后驹止,稍微滑動(dòng)后立即松開    
onDown-----》onScroll----》onScroll----》onScroll----》………----->onFling    
拖動(dòng)    
onDown------》onScroll----》onScroll------》onFiling
    可見,無論是滑屏观蜗,還是拖動(dòng)臊恋,影響的只是中間OnScroll觸發(fā)的數(shù)量多少而已,最終都會(huì)觸發(fā)onFling事件墓捻!

**2抖仅、實(shí)例**
要使用GestureDetector,有三步要走:

1砖第、創(chuàng)建OnGestureListener監(jiān)聽函數(shù):
可以使用構(gòu)造實(shí)例:

GestureDetector.OnGestureListener listener = new GestureDetector.OnGestureListener(){

};  ```

也可以構(gòu)造類:

private class gestureListener implements GestureDetector.OnGestureListener{  
  
}  ```
2撤卢、創(chuàng)建GestureDetector實(shí)例mGestureDetector:
構(gòu)造函數(shù)有下面三個(gè),根據(jù)需要選擇:

GestureDetector gestureDetector=new GestureDetector(GestureDetector.OnGestureListener listener);
GestureDetector gestureDetector=new GestureDetector(Context context,GestureDetector.OnGestureListener listener);
GestureDetector gestureDetector=new GestureDetector(Context context,GestureDetector.SimpleOnGestureListener listener); ```
3厂画、onTouch(View v, MotionEvent event)中攔截:

public boolean onTouch(View v, MotionEvent event) {  
    return mGestureDetector.onTouchEvent(event);     
}  ```
4、控件綁定

imageView = (ImageView)findViewById(R.id.imager);
imageView.setImageBitmap(BitmapFactory.decodeResource(this.getResources(),R.drawable.a)); ```
現(xiàn)在進(jìn)入實(shí)例階段:
首先拷邢,在主布局頁面添加一個(gè)ImageView代碼為:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerInside"
        android:id="@+id/imager"
        android:src="@drawable/a"
        />

</LinearLayout>

然后在JAVA代碼中袱院,依據(jù)上面的原則

package com.liaxi.dell.gesture;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.widget.ImageView;

public class MainActivity extends Activity implements GestureDetector.OnGestureListener {

    //定義手勢(shì)檢測(cè)器實(shí)例
    GestureDetector detector;
    ImageView imageView;
    //初始的圖片資源
    Bitmap bitmap;
    //定義圖片的寬、高
    int width,height;
    //記錄當(dāng)前的縮放比例
    float currentScale = 1;
    //控制圖片縮放的Matrx 對(duì)象
    Matrix matrix;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //創(chuàng)建手勢(shì)檢測(cè)器
        detector = new GestureDetector(this,this);
        imageView  = (ImageView)findViewById(R.id.imager);
        matrix = new Matrix();
        //獲取被縮放的原圖片
        bitmap = BitmapFactory.decodeResource(
                this.getResources(),R.drawable.a
        );
        //獲得位圖寬
        width = bitmap.getWidth();
        //獲得位圖高
        height = bitmap.getHeight();
        //設(shè)置ImaeView初始化時(shí)顯示的圖片
        imageView.setImageBitmap(BitmapFactory.decodeResource(this.getResources(),R.drawable.a));
    }

    @Override
    public boolean onTouchEvent(MotionEvent me) {
        //將該Activity上的觸碰事件交給GesturDetector處理
        return detector.onTouchEvent(me);
    }

    @Override
    public boolean onDown(MotionEvent e) {
        return false;
    }

    @Override
    public void onShowPress(MotionEvent e) {

    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return false;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        return false;
    }

    @Override
    public void onLongPress(MotionEvent e) {

    }

    @Override
    public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) {
        velocityX = velocityX > 4000 ? 4000 : velocityX;
        velocityX = velocityX < -4000 ? -4000 : velocityX;
        //根據(jù)手勢(shì)的速度來計(jì)算縮放比,如果velocityX>0,放大圖像忽洛,否則縮小圖像
        currentScale += currentScale * velocityX / 4000.0f;
        //重置Matrix
        matrix.reset();
        //縮放Matrix
        matrix.setScale(currentScale,currentScale,160,200);
        BitmapDrawable tmp = (BitmapDrawable)imageView.getDrawable();
        //如狗圖片還未收回腻惠,先強(qiáng)制收回該圖片
        if(!tmp.getBitmap().isRecycled())
        {
            tmp.getBitmap().recycle();
        }
        //根據(jù)原始位圖和Matrix創(chuàng)建新圖片
        Bitmap bitmap2 = Bitmap.createBitmap(bitmap,0,0,width,height,matrix,true);
        //顯示新的位圖
        imageView.setImageBitmap(bitmap2);
        return true;
    }
}

該示例的程序界面布局很簡(jiǎn)單,只在界面中間定義一個(gè)ImageView來顯示圖片即可欲虚。該程序的思路是使用一個(gè)GestureDetector來檢測(cè)用戶的手勢(shì)集灌,并根據(jù)用戶手勢(shì)在橫向的速度縮放圖片。
該程序的不同之處在于:程序?qū)崿F(xiàn)GestureDetector.OnGestureListener監(jiān)聽器時(shí)复哆,只實(shí)現(xiàn)了onFling(MotionEvent event1,MotionEvent even2,floatvelocityX,float veloctiyY)方法欣喧,并在該方法內(nèi)根據(jù)velocityX參數(shù)(橫向上的拖動(dòng)速度)來計(jì)算圖片的縮放比,這樣該程序即可根據(jù)用戶的“手勢(shì)”來縮放圖片梯找。

ezgif-1-9471e7e52f.gif

源碼下載:https://github.com/gb0302/Gesture

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末唆阿,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子锈锤,更是在濱河造成了極大的恐慌驯鳖,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件久免,死亡現(xiàn)場(chǎng)離奇詭異浅辙,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)阎姥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門记舆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人丁寄,你說我怎么就攤上這事氨淌。” “怎么了伊磺?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵盛正,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我屑埋,道長(zhǎng)豪筝,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任摘能,我火速辦了婚禮续崖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘团搞。我一直安慰自己严望,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布逻恐。 她就那樣靜靜地躺著像吻,像睡著了一般峻黍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拨匆,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天姆涩,我揣著相機(jī)與錄音,去河邊找鬼惭每。 笑死骨饿,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的台腥。 我是一名探鬼主播宏赘,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼览爵!你這毒婦竟也來了置鼻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤蜓竹,失蹤者是張志新(化名)和其女友劉穎箕母,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俱济,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嘶是,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蛛碌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片聂喇。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蔚携,靈堂內(nèi)的尸體忽然破棺而出希太,到底是詐尸還是另有隱情,我是刑警寧澤酝蜒,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布誊辉,位于F島的核電站,受9級(jí)特大地震影響亡脑,放射性物質(zhì)發(fā)生泄漏堕澄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一霉咨、第九天 我趴在偏房一處隱蔽的房頂上張望蛙紫。 院中可真熱鬧,春花似錦途戒、人聲如沸坑傅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽唁毒。三九已至矢渊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間枉证,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工移必, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留室谚,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓崔泵,卻偏偏與公主長(zhǎng)得像秒赤,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子憎瘸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容