一棘利、概述
當(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ì)”來縮放圖片梯找。