日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android笔记:触摸事件的分析与总结----多点触控

發(fā)布時(shí)間:2023/12/29 Android 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android笔记:触摸事件的分析与总结----多点触控 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.


? ?其他相關(guān)博文:

? ?Android筆記:觸摸事件的分析與總結(jié)----MotionEvent對(duì)象

? ?Android筆記:觸摸事件的分析與總結(jié)----TouchEvent處理機(jī)制

????Android筆記:觸摸事件的分析與總結(jié)----多點(diǎn)觸控



一、多點(diǎn)觸控

? ? 當(dāng)多點(diǎn)同時(shí)觸摸屏幕時(shí),系統(tǒng)將會(huì)產(chǎn)生如下的觸摸事件:

? ? 1.ACTION_DOWN:觸摸屏幕的第一個(gè)點(diǎn)。此時(shí)手勢開始。該點(diǎn)的數(shù)據(jù)通常在MotionEvent事件隊(duì)列索引位置0處。

? ? 2.ACTION_POINTER_DOWN:除了第一個(gè)點(diǎn)的其他觸摸點(diǎn)數(shù)據(jù)。該點(diǎn)的數(shù)據(jù)的索引位置由getActionIndex()方法返回。

? ? 3.ACTION_MOVE:在手勢過程中發(fā)生的一次變化。

? ? 4.ACTION_POINTER_UP:當(dāng)不是第一個(gè)點(diǎn)的其他點(diǎn)UP后觸發(fā)。

? ? 5.ACTION_UP:當(dāng)手勢中的最后一個(gè)點(diǎn)離開屏幕。


簡單測試范例


布局xml代碼如下:

<RelativeLayout?xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/layout1"android:layout_width="match_parent"android:layout_height="match_parent"android:tag="true布局"tools:context=".MainActivity"?><TextViewandroid:id="@+id/message"android:layout_width="wrap_content"android:layout_height="wrap_content"android:tag="true控件"android:text="@string/hello_world"?/></RelativeLayout>


java代碼如下:

package?com.lonshine.d_touchduodian;import?android.os.Bundle; import?android.app.Activity; import?android.util.Log; import?android.view.MotionEvent; import?android.view.View; import?android.view.View.OnTouchListener; import?android.widget.RelativeLayout;public?class?MainActivity?extends?Activity?implements?OnTouchListener?? {@Overrideprotected?void?onCreate(Bundle?savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);RelativeLayout?layout?=?(RelativeLayout)?findViewById(R.id.layout1);layout.setOnTouchListener(this);}@Overridepublic?boolean?onTouch(View?v,?MotionEvent?event){String?tag?=?v.getTag().toString();Log.e(tag,?"**********************************************");Log.e(tag,?"**********************************************");Log.e(tag,?"觸摸的是:"?+?tag);Log.e(tag,?describeEvent(event));logAction(event);Log.e(tag,?"**********************************************");Log.e(tag,?"**********************************************");Log.e("",?"????????????????????????");Log.e("",?"????????????????????????");if("true".equals(tag.substring(0,?4))){return?true;}else{return?false;}}protected?static?String?describeEvent(MotionEvent?event){StringBuilder?sb?=?new?StringBuilder(500);sb.append("Action:?").append(event.getAction()).append("\n");//?獲取觸控動(dòng)作比如ACTION_DOWNint?count?=?event.getPointerCount();sb.append("觸點(diǎn)個(gè)數(shù):?").append(count).append("\n");int?i?=?0;while?(i?<?count){sb.append("-------------------------").append("\n");int?pointerId?=?event.getPointerId(i);sb.append("觸點(diǎn)序號(hào):?").append(i).append("\n");sb.append("觸點(diǎn)ID?:?").append(pointerId).append("\n");sb.append("相對(duì)坐標(biāo):?").append(event.getX(i)).append("??*??").append(event.getY(i)).append("\n");sb.append("壓力???????:?").append(event.getPressure(i)).append("\n");//?壓力值,0-1之間,看情況,很可能始終返回1sb.append("范圍大小:?").append(event.getSize(i)).append("\n");//?指壓范圍i++;sb.append("-------------------------").append("\n");}sb.append("按下時(shí)間:?").append(event.getDownTime()).append("ms???");sb.append("結(jié)束時(shí)間:?").append(event.getEventTime()).append("ms???");sb.append("運(yùn)行時(shí)間:?").append(event.getEventTime()?-?event.getDownTime()).append("ms\n");return?sb.toString();}private?void?logAction(MotionEvent?event){int?masked?=?event.getActionMasked();int?index?=?event.getActionIndex();int?pointerId?=?event.getPointerId(index);if(masked?==?5?||?masked?==?6){masked?=?masked?-?5;}Log.e("Action",?"觸點(diǎn)序號(hào):?"?+?index);Log.e("Action",?"觸點(diǎn)ID?:??"?+?pointerId);Log.e("Action",?"ActionMasked?:"?+?masked);}}


多點(diǎn)觸控的日志打印出來太多,此處僅針對(duì)日志輸出作簡單分析:

A.按下第一根手指時(shí),獲得一個(gè)索引為0且指針I(yè)D為0的指針(ACTION_DOWN = 0);

B.接下去action輸出為2(ACTION_MOVE),此時(shí)仍然僅有一個(gè)指針,并且索引和ID都為0;

C.然后按下第二根手指,action值輸出為261。此值由兩部分組成:一個(gè)是指針?biāo)饕?#xff0c;一個(gè)是指針正在執(zhí)行何種操作;

D.將十進(jìn)制261轉(zhuǎn)換為十六進(jìn)制數(shù)為0x00000105。其中01代表指針?biāo)饕?#xff0c;05代表操作值(即ACTION_POINTER_DOWN的值,用于多點(diǎn)觸摸場景);

E.依此類推,當(dāng)按下第三根手指時(shí)action輸出值為0x00000205(十進(jìn)制517),第四根則為0x000305(十進(jìn)制773);

F.當(dāng)?shù)谝桓种鸽x開屏幕時(shí),action值為0x00000006(十進(jìn)制6),即索引為0,操作值為6(即ACTION_POINTER_UP);

G.如果此時(shí)第二根手指離開時(shí),action值應(yīng)該為0x00000106(十進(jìn)制262),因?yàn)榇藭r(shí)仍然擁有兩根手指的信息;

H.而實(shí)際結(jié)果并沒有得到262的action值,這是因?yàn)楫?dāng)?shù)谝桓种鸽x開屏幕后,第二根手指的索引從1更改成了0,但是指針I(yè)D仍然為1.

I.對(duì)于每一次移動(dòng),action值將始終為2,因?yàn)锳CTION_MOVE事件并沒有包含哪根手指在移動(dòng)的信息。


附:依次按下四根手指的日志





其他小結(jié):

(1)getPointerCount() 獲得觸屏的點(diǎn)數(shù),

? ?getActionIndex()獲得觸點(diǎn)的指針?biāo)饕?#xff0c;

? ?getPointerId(index)獲得指針?biāo)饕龑?duì)應(yīng)的觸點(diǎn)ID;


(2)getActionMasked()表示用于多點(diǎn)觸控檢測點(diǎn)。而在1.6和2.1中并沒有event.getActionMasked()這個(gè)方法,其實(shí)他就是把event.getAction()& MotionEvent.ACTION_MASK封裝了一下。






二、其他參考范例:

(一)單點(diǎn)觸摸拖動(dòng)圖片與多點(diǎn)觸摸縮放圖片

package?com.lonshine.touchdemo;import?android.app.Activity; import?android.content.Context; import?android.graphics.*; import?android.graphics.drawable.BitmapDrawable; import?android.os.Bundle; import?android.view.MotionEvent; import?android.widget.ImageView; import?android.widget.ImageView.ScaleType;/***?多點(diǎn)觸控來控制ImageView中圖像的放大與縮小,?單點(diǎn)觸控則用來拖動(dòng)圖片*?*?@author?zeng*?*/ public?class?MainActivity?extends?Activity {private?MyImageView?p_w_picpathView;private?Bitmap?bitmap;//?兩點(diǎn)觸屏后之間的長度private?float?beforeLenght;private?float?afterLenght;//?單點(diǎn)移動(dòng)的前后坐標(biāo)值private?float?afterX,?afterY;private?float?beforeX,?beforeY;/**?Called?when?the?activity?is?first?created.?*/@Overridepublic?void?onCreate(Bundle?savedInstanceState){super.onCreate(savedInstanceState);findView();setContentView(p_w_picpathView);config();}private?void?findView(){p_w_picpathView?=?new?MyImageView(this);//?獲得圖片bitmap?=?((BitmapDrawable)?getResources().getDrawable(R.drawable.xing)).getBitmap();}private?void?config(){//?設(shè)置p_w_picpathView的顯示圖片p_w_picpathView.setImageBitmap(bitmap);//?設(shè)置圖片填充ImageViewp_w_picpathView.setScaleType(ScaleType.FIT_XY);}//?創(chuàng)建一個(gè)自己的ImageView類class?MyImageView?extends?ImageView{private?float?scale?=?0.1f;public?MyImageView(Context?context){super(context);}//?用來設(shè)置ImageView的位置private?void?setLocation(int?x,?int?y){this.setFrame(this.getLeft()?+?x,?this.getTop()?+?y,?this.getRight()?+?x,?this.getBottom()?+?y);}/***?用來放大縮小ImageView?因?yàn)閳D片是填充ImageView的,所以也就有放大縮小圖片的效果?flag為0是放大圖片,為1是縮小圖片*/private?void?setScale(float?temp,?int?flag){if?(flag?==?0){this.setFrame(this.getLeft()?-?(int)?(temp?*?this.getWidth()),?this.getTop()?-?(int)?(temp?*?this.getHeight()),?this.getRight()+?(int)?(temp?*?this.getWidth()),?this.getBottom()?+?(int)?(temp?*?this.getHeight()));}else{this.setFrame(this.getLeft()?+?(int)?(temp?*?this.getWidth()),?this.getTop()?+?(int)?(temp?*?this.getHeight()),?this.getRight()-?(int)?(temp?*?this.getWidth()),?this.getBottom()?-?(int)?(temp?*?this.getHeight()));}}//?繪制邊框@Overrideprotected?void?onDraw(Canvas?canvas){super.onDraw(canvas);Rect?rec?=?canvas.getClipBounds();rec.bottom--;rec.right--;Paint?paint?=?new?Paint();paint.setColor(Color.RED);paint.setStyle(Paint.Style.STROKE);canvas.drawRect(rec,?paint);}/***?讓圖片跟隨手指觸屏的位置移動(dòng)?beforeX、Y是用來保存前一位置的坐標(biāo)?afterX、Y是用來保存當(dāng)前位置的坐標(biāo)*?它們的差值就是ImageView各坐標(biāo)的增加或減少值*/public?void?moveWithFinger(MotionEvent?event){switch?(event.getAction()){case?MotionEvent.ACTION_DOWN:beforeX?=?event.getX();beforeY?=?event.getY();break;case?MotionEvent.ACTION_MOVE:afterX?=?event.getX();afterY?=?event.getY();this.setLocation((int)?(afterX?-?beforeX),?(int)?(afterY?-?beforeY));beforeX?=?afterX;beforeY?=?afterY;break;case?MotionEvent.ACTION_UP:break;}}/***?通過多點(diǎn)觸屏放大或縮小圖像?beforeLenght用來保存前一時(shí)間兩點(diǎn)之間的距離?afterLenght用來保存當(dāng)前時(shí)間兩點(diǎn)之間的距離*/public?void?scaleWithFinger(MotionEvent?event){float?moveX?=?event.getX(1)?-?event.getX(0);float?moveY?=?event.getY(1)?-?event.getY(0);switch?(event.getAction()){case?MotionEvent.ACTION_DOWN:beforeLenght?=?(float)?Math.sqrt((moveX?*?moveX)?+?(moveY?*?moveY));break;case?MotionEvent.ACTION_MOVE://?得到兩個(gè)點(diǎn)之間的長度afterLenght?=?(float)?Math.sqrt((moveX?*?moveX)?+?(moveY?*?moveY));float?gapLenght?=?afterLenght?-?beforeLenght;if?(gapLenght?==?0){break;}//?如果當(dāng)前時(shí)間兩點(diǎn)距離大于前一時(shí)間兩點(diǎn)距離,則傳0,否則傳1if?(gapLenght?>?0){this.setScale(scale,?0);}else{this.setScale(scale,?1);}beforeLenght?=?afterLenght;break;}}}//?這里來監(jiān)聽屏幕觸控時(shí)間@Overridepublic?boolean?onTouchEvent(MotionEvent?event){/***?判定用戶是否觸摸到了圖片?如果是單點(diǎn)觸摸則調(diào)用控制圖片移動(dòng)的方法?如果是2點(diǎn)觸控則調(diào)用控制圖片大小的方法*/if?(event.getY()?>?p_w_picpathView.getTop()?&&?event.getY()?<?p_w_picpathView.getBottom()?&&?event.getX()?>?p_w_picpathView.getLeft()&&?event.getX()?<?p_w_picpathView.getRight()){if?(event.getPointerCount()?==?2){p_w_picpathView.scaleWithFinger(event);}else?if?(event.getPointerCount()?==?1){p_w_picpathView.moveWithFinger(event);}}return?true;}}


范例參考自:http://blog.csdn.net/ldj299/article/details/6422547




(二)實(shí)現(xiàn)多點(diǎn)消息攔截,用于多個(gè)物體拖動(dòng)等效果

package?com.lonshine.d_touchdemo;import?java.util.ArrayList; import?java.util.List; import?android.content.Context; import?android.os.Handler; import?android.os.Message; import?android.view.MotionEvent; import?android.view.VelocityTracker; import?android.view.ViewConfiguration;/***?實(shí)現(xiàn)多點(diǎn)消息攔截,用于多個(gè)物體拖動(dòng)等效果*?@author?zeng*/ public?class?MultiTouchGestureDetector {@SuppressWarnings("unused")private?static?final?String?MYTAG?=?"Alan";public?static?final?String?CLASS_NAME?=?"MultiTouchGestureDetector";/***?事件信息類?<br/>*?用來記錄一個(gè)手勢*/private?class?EventInfo{private?MultiMotionEvent?mCurrentDownEvent;?//?當(dāng)前的down事件private?MultiMotionEvent?mPreviousUpEvent;?//?上一次up事件private?boolean?mStillDown;?//?當(dāng)前手指是否還在屏幕上private?boolean?mInLongPress;?//?當(dāng)前事件是否屬于長按手勢private?boolean?mAlwaysInTapRegion;?//?是否當(dāng)前手指僅在小范圍內(nèi)移動(dòng),當(dāng)手指僅在小范圍內(nèi)移動(dòng)時(shí),視為手指未曾移動(dòng)過,不會(huì)觸發(fā)onScroll手勢private?boolean?mAlwaysInBiggerTapRegion;?//?是否當(dāng)前手指在較大范圍內(nèi)移動(dòng),僅當(dāng)此值為true時(shí),雙擊手勢才能成立private?boolean?mIsDoubleTapping;?//?當(dāng)前手勢,是否為雙擊手勢private?float?mLastMotionY;?//?最后一次事件的X坐標(biāo)private?float?mLastMotionX;?//?最后一次事件的Y坐標(biāo)private?EventInfo(MotionEvent?e){this(new?MultiMotionEvent(e));}private?EventInfo(MultiMotionEvent?me){mCurrentDownEvent?=?me;mStillDown?=?true;mInLongPress?=?false;mAlwaysInTapRegion?=?true;mAlwaysInBiggerTapRegion?=?true;mIsDoubleTapping?=?false;}//?釋放MotionEven對(duì)象,使系統(tǒng)能夠繼續(xù)使用它們public?void?recycle(){if?(mCurrentDownEvent?!=?null){mCurrentDownEvent.recycle();mCurrentDownEvent?=?null;}if?(mPreviousUpEvent?!=?null){mPreviousUpEvent.recycle();mPreviousUpEvent?=?null;}}@Overridepublic?void?finalize(){this.recycle();}}/***?多點(diǎn)事件類?<br/>*?將一個(gè)多點(diǎn)事件拆分為多個(gè)單點(diǎn)事件,并方便獲得事件的絕對(duì)坐標(biāo)?<br/>*?絕對(duì)坐標(biāo)用以在界面中找到觸點(diǎn)所在的控件*?*?@author?ray-ni*/public?class?MultiMotionEvent{private?MotionEvent?mEvent;private?int?mIndex;private?MultiMotionEvent(MotionEvent?e){mEvent?=?e;mIndex?=?(e.getAction()?&?MotionEvent.ACTION_POINTER_ID_MASK)?>>?MotionEvent.ACTION_POINTER_ID_SHIFT;?//?等效于//?mEvent.getActionIndex();}private?MultiMotionEvent(MotionEvent?e,?int?idx){mEvent?=?e;mIndex?=?idx;}//?行為public?int?getAction(){int?action?=?mEvent.getAction()?&?MotionEvent.ACTION_MASK;?//?等效于//?mEvent.getActionMasked();switch?(action){case?MotionEvent.ACTION_POINTER_DOWN:action?=?MotionEvent.ACTION_DOWN;break;case?MotionEvent.ACTION_POINTER_UP:action?=?MotionEvent.ACTION_UP;break;}return?action;}//?返回X的絕對(duì)坐標(biāo)public?float?getX(){return?mEvent.getX(mIndex)?+?mEvent.getRawX()?-?mEvent.getX();}//?返回Y的絕對(duì)坐標(biāo)public?float?getY(){return?mEvent.getY(mIndex)?+?mEvent.getRawY()?-?mEvent.getY();}//?事件發(fā)生的時(shí)間public?long?getEventTime(){return?mEvent.getEventTime();}//?事件序號(hào)public?int?getIndex(){return?mIndex;}//?事件IDpublic?int?getId(){return?mEvent.getPointerId(mIndex);}//?釋放事件對(duì)象,使系統(tǒng)能夠繼續(xù)使用public?void?recycle(){if?(mEvent?!=?null){mEvent.recycle();mEvent?=?null;}}}//?多點(diǎn)手勢監(jiān)聽器public?interface?MultiTouchGestureListener{//?手指觸碰到屏幕,由一個(gè)?ACTION_DOWN觸發(fā)boolean?onDown(MultiMotionEvent?e);//?確定一個(gè)press事件,強(qiáng)調(diào)手指按下的一段時(shí)間(TAP_TIMEOUT)內(nèi),手指未曾移動(dòng)或抬起void?onShowPress(MultiMotionEvent?e);//?手指點(diǎn)擊屏幕后離開,由?ACTION_UP引發(fā),可以簡單的理解為單擊事件,即手指點(diǎn)擊時(shí)間不長(未構(gòu)成長按事件),也不曾移動(dòng)過boolean?onSingleTapUp(MultiMotionEvent?e);//?長按,手指點(diǎn)下后一段時(shí)間(DOUBLE_TAP_TIMEOUT)內(nèi),不曾抬起或移動(dòng)void?onLongPress(MultiMotionEvent?e);//?拖動(dòng),由ACTION_MOVE觸發(fā),手指地按下后,在屏幕上移動(dòng)boolean?onScroll(MultiMotionEvent?e1,?MultiMotionEvent?e2,?float?distanceX,?float?distanceY);//?滑動(dòng),由ACTION_UP觸發(fā),手指按下并移動(dòng)一段距離后,抬起時(shí)觸發(fā)boolean?onFling(MultiMotionEvent?e1,?MultiMotionEvent?e2,?float?velocityX,?float?velocityY);}//?多點(diǎn)雙擊監(jiān)聽器public?interface?MultiTouchDoubleTapListener{//?單擊事件確認(rèn),強(qiáng)調(diào)第一個(gè)單擊事件發(fā)生后,一段時(shí)間內(nèi),未發(fā)生第二次單擊事件,即確定不會(huì)觸發(fā)雙擊事件boolean?onSingleTapConfirmed(MultiMotionEvent?e);//?雙擊事件,//?由ACTION_DOWN觸發(fā),從第一次單擊事件的DOWN事件開始的一段時(shí)間(DOUBLE_TAP_TIMEOUT)內(nèi)結(jié)束(即手指),//?并且在第一次單擊事件的UP時(shí)間開始后的一段時(shí)間內(nèi)(DOUBLE_TAP_TIMEOUT)發(fā)生第二次單擊事件,//?除此之外兩者坐標(biāo)間距小于定值(DOUBLE_TAP_SLAP)時(shí),則觸發(fā)雙擊事件boolean?onDoubleTap(MultiMotionEvent?e);//?雙擊事件,與onDoubleTap事件不同之處在于,構(gòu)成雙擊的第二次點(diǎn)擊的ACTION_DOWN,ACTION_MOVE和ACTION_UP都會(huì)觸發(fā)該事件boolean?onDoubleTapEvent(MultiMotionEvent?e);}//?事件信息隊(duì)列,隊(duì)列的下標(biāo)與MotionEvent的pointId對(duì)應(yīng)private?static?List<EventInfo>?sEventInfos?=?new?ArrayList<EventInfo>(10);//?雙擊判斷隊(duì)列,這個(gè)隊(duì)列中的元素等待雙擊超時(shí)的判斷結(jié)果private?static?List<EventInfo>?sEventForDoubleTap?=?new?ArrayList<EventInfo>(5);//?指定大點(diǎn)擊區(qū)域的大小(這個(gè)比較拗口),這個(gè)值主要用于幫助判斷雙擊是否成立private?int?mBiggerTouchSlopSquare?=?20?*?20;//?判斷是否構(gòu)成onScroll手勢,當(dāng)手指在這個(gè)范圍內(nèi)移動(dòng)時(shí),不觸發(fā)onScroll手勢private?int?mTouchSlopSquare;//?判斷是否構(gòu)成雙擊,只有兩次點(diǎn)擊的距離小于該值,才能構(gòu)成雙擊手勢private?int?mDoubleTapSlopSquare;//?最小滑動(dòng)速度private?int?mMinimumFlingVelocity;//?最大滑動(dòng)速度private?int?mMaximumFlingVelocity;//?長按閥值,當(dāng)手指按下后,在該閥值的時(shí)間內(nèi),未移動(dòng)超過mTouchSlopSquare的距離并未抬起,則長按手勢觸發(fā)private?static?final?int?LONGPRESS_TIMEOUT?=?ViewConfiguration.getLongPressTimeout();//?showPress手勢的觸發(fā)閥值,當(dāng)手指按下后,在該閥值的時(shí)間內(nèi),未移動(dòng)超過mTouchSlopSquare的距離并未抬起,則showPress手勢觸發(fā)private?static?final?int?TAP_TIMEOUT?=?ViewConfiguration.getTapTimeout();//?雙擊超時(shí)閥值,僅在兩次雙擊事件的間隔(第一次單擊的UP事件和第二次單擊的DOWN事件)小于此閥值,雙擊事件才能成立private?static?final?int?DOUBLE_TAP_TIMEOUT?=?ViewConfiguration.getDoubleTapTimeout();//?雙擊區(qū)域閥值,僅在兩次雙擊事件的距離小于此閥值,雙擊事件才能成立private?static?final?int?DOUBLE_TAP_SLAP?=?64;//?GestureHandler所處理的Message的what屬性可能為以下?常量://?showPress手勢private?static?final?int?SHOW_PRESS?=?1;//?長按手勢private?static?final?int?LONG_PRESS?=?2;//?SingleTapConfirmed手勢private?static?final?int?TAP_SINGLE?=?3;//?雙擊手勢private?static?final?int?TAP_DOUBLE?=?4;//?手勢處理器private?final?GestureHandler?mHandler;//?手勢監(jiān)聽器private?final?MultiTouchGestureListener?mListener;//?雙擊監(jiān)聽器private?MultiTouchDoubleTapListener?mDoubleTapListener;//?長按允許閥值private?boolean?mIsLongpressEnabled;//?速度追蹤器private?VelocityTracker?mVelocityTracker;private?class?GestureHandler?extends?Handler{GestureHandler(){super();}GestureHandler(Handler?handler){super(handler.getLooper());}@Overridepublic?void?handleMessage(Message?msg){int?idx?=?(Integer)?msg.obj;switch?(msg.what){case?SHOW_PRESS:{if?(idx?>=?sEventInfos.size()){//?Log.w(MYTAG,?CLASS_NAME?+//?":handleMessage,?msg.what?=?SHOW_PRESS,?idx="?+?idx?+//?",?while?sEventInfos.size()="//?+?sEventInfos.size());break;}EventInfo?info?=?sEventInfos.get(idx);if?(info?==?null){//?Log.e(MYTAG,?CLASS_NAME?+//?":handleMessage,?msg.what?=?SHOW_PRESS,?idx="?+?idx?+//?",?Info?=?null");break;}//?觸發(fā)手勢監(jiān)聽器的onShowPress事件mListener.onShowPress(info.mCurrentDownEvent);break;}case?LONG_PRESS:{//?Log.d(MYTAG,?CLASS_NAME?+?":trigger?LONG_PRESS");if?(idx?>=?sEventInfos.size()){//?Log.w(MYTAG,?CLASS_NAME?+//?":handleMessage,?msg.what?=?LONG_PRESS,?idx="?+?idx?+//?",?while?sEventInfos.size()="//?+?sEventInfos.size());break;}EventInfo?info?=?sEventInfos.get(idx);if?(info?==?null){//?Log.e(MYTAG,?CLASS_NAME?+//?":handleMessage,?msg.what?=?LONG_PRESS,?idx="?+?idx?+//?",?Info?=?null");break;}dispatchLongPress(info,?idx);break;}case?TAP_SINGLE:{//?Log.d(MYTAG,?CLASS_NAME?+?":trriger?TAP_SINGLE");//?If?the?user's?finger?is?still?down,?do?not?count?it?as?a//?tapif?(idx?>=?sEventInfos.size()){//?Log.e(MYTAG,?CLASS_NAME?+//?":handleMessage,?msg.what?=?TAP_SINGLE,?idx="?+?idx?+//?",?while?sEventInfos.size()="//?+?sEventInfos.size());break;}EventInfo?info?=?sEventInfos.get(idx);if?(info?==?null){//?Log.e(MYTAG,?CLASS_NAME?+//?":handleMessage,?msg.what?=?TAP_SINGLE,?idx="?+?idx?+//?",?Info?=?null");break;}if?(mDoubleTapListener?!=?null?&&?!info.mStillDown){?//?手指在雙擊超時(shí)的閥值內(nèi)未離開屏幕進(jìn)行第二次單擊事件,則確定單擊事件成立(不再觸發(fā)雙擊事件)mDoubleTapListener.onSingleTapConfirmed(info.mCurrentDownEvent);}break;}case?TAP_DOUBLE:{if?(idx?>=?sEventForDoubleTap.size()){//?Log.w(MYTAG,?CLASS_NAME?+//?":handleMessage,?msg.what?=?TAP_DOUBLE,?idx="?+?idx?+//?",?while?sEventForDoubleTap.size()="//?+?sEventForDoubleTap.size());break;}EventInfo?info?=?sEventForDoubleTap.get(idx);if?(info?==?null){//?Log.w(MYTAG,?CLASS_NAME?+//?":handleMessage,?msg.what?=?TAP_DOUBLE,?idx="?+?idx?+//?",?Info?=?null");break;}sEventForDoubleTap.set(idx,?null);//?這個(gè)沒什么好做的,就是把隊(duì)列中對(duì)應(yīng)的元素清除而已break;}default:throw?new?RuntimeException("Unknown?message?"?+?msg);?//?never}}}/***?觸發(fā)長按事件*?*?@param?info*?@param?idx*/private?void?dispatchLongPress(EventInfo?info,?int?idx){mHandler.removeMessages(TAP_SINGLE,?idx);//?移除單擊事件確認(rèn)info.mInLongPress?=?true;mListener.onLongPress(info.mCurrentDownEvent);}/***?構(gòu)造器1*?*?@param?context*?@param?listener*/public?MultiTouchGestureDetector(Context?context,?MultiTouchGestureListener?listener){this(context,?listener,?null);}/***?構(gòu)造器2*?*?@param?context*?@param?listener*?@param?handler*/public?MultiTouchGestureDetector(Context?context,?MultiTouchGestureListener?listener,?Handler?handler){if?(handler?!=?null){mHandler?=?new?GestureHandler(handler);}else{mHandler?=?new?GestureHandler();}mListener?=?listener;if?(listener?instanceof?MultiTouchDoubleTapListener){setOnDoubleTapListener((MultiTouchDoubleTapListener)?listener);}init(context);}/***?初始化識(shí)別器*?*?@param?context*/private?void?init(Context?context){if?(mListener?==?null){throw?new?NullPointerException("OnGestureListener?must?not?be?null");}mIsLongpressEnabled?=?true;int?touchSlop,?doubleTapSlop;if?(context?==?null){touchSlop?=?ViewConfiguration.getTouchSlop();doubleTapSlop?=?DOUBLE_TAP_SLAP;mMinimumFlingVelocity?=?ViewConfiguration.getMinimumFlingVelocity();mMaximumFlingVelocity?=?ViewConfiguration.getMaximumFlingVelocity();}else{//?允許識(shí)別器在App中,使用偏好的設(shè)定final?ViewConfiguration?configuration?=?ViewConfiguration.get(context);touchSlop?=?configuration.getScaledTouchSlop();doubleTapSlop?=?configuration.getScaledDoubleTapSlop();mMinimumFlingVelocity?=?configuration.getScaledMinimumFlingVelocity();mMaximumFlingVelocity?=?configuration.getScaledMaximumFlingVelocity();}mTouchSlopSquare?=?touchSlop?*?touchSlop?/?16;mDoubleTapSlopSquare?=?doubleTapSlop?*?doubleTapSlop;}/***?設(shè)置雙擊監(jiān)聽器*?*?@param?onDoubleTapListener*/public?void?setOnDoubleTapListener(MultiTouchDoubleTapListener?onDoubleTapListener){mDoubleTapListener?=?onDoubleTapListener;}/***?設(shè)置是否允許長按*?*?@param?isLongpressEnabled*/public?void?setIsLongpressEnabled(boolean?isLongpressEnabled){mIsLongpressEnabled?=?isLongpressEnabled;}/***?判斷是否允許長按*?*?@return*/public?boolean?isLongpressEnabled(){return?mIsLongpressEnabled;}/***?判斷當(dāng)前事件是否為雙擊事件?<br/>*?通過遍歷sEventForDoubleTap來匹配是否存在能夠構(gòu)成雙擊事件的單擊事件*?*?@param?e*?@return*/private?EventInfo?checkForDoubleTap(MultiMotionEvent?e){if?(sEventForDoubleTap.isEmpty()){//?Log.e(MYTAG,?CLASS_NAME?+//?":checkForDoubleTap(),?sEventForDoubleTap?is?empty?!");return?null;}for?(int?i?=?0;?i?<?sEventForDoubleTap.size();?i++){EventInfo?info?=?sEventForDoubleTap.get(i);if?(info?!=?null?&&?isConsideredDoubleTap(info,?e)){sEventForDoubleTap.set(i,?null);//?這個(gè)單擊事件已經(jīng)被消耗了,所以置為nullmHandler.removeMessages(TAP_DOUBLE,?i);//?移除Handler內(nèi)的為處理消息return?info;}}return?null;}/***?判斷當(dāng)前按下事件是否能和指定的單擊事件構(gòu)成雙擊事件*?*?@param?info*?@param?secondDown*?@return*/private?boolean?isConsideredDoubleTap(EventInfo?info,?MultiMotionEvent?secondDown){if?(!info.mAlwaysInBiggerTapRegion){?//?如多第一次單擊事件有過較大距離的移動(dòng),則無法構(gòu)成雙擊事件return?false;}if?(secondDown.getEventTime()?-?info.mPreviousUpEvent.getEventTime()?>?DOUBLE_TAP_TIMEOUT){//?如果第一次單擊的UP時(shí)間和第二次單擊的down時(shí)間時(shí)間間隔大于DOUBLE_TAP_TIMEOUT,也無法構(gòu)成雙擊事件return?false;}int?deltaX?=?(int)?info.mCurrentDownEvent.getX()?-?(int)?secondDown.getX();int?deltaY?=?(int)?info.mCurrentDownEvent.getY()?-?(int)?secondDown.getY();return?(deltaX?*?deltaX?+?deltaY?*?deltaY?<?mDoubleTapSlopSquare);//?最后判斷兩次單擊事件的距離}/***?將事件信息放入雙擊判斷隊(duì)列,并返回序號(hào)*?*?@param?info*?@return*/private?int?addIntoTheMinIndex(EventInfo?info){for?(int?i?=?0;?i?<?sEventForDoubleTap.size();?i++){if?(sEventForDoubleTap.get(i)?==?null){sEventForDoubleTap.set(i,?info);return?i;}}sEventForDoubleTap.add(info);return?sEventForDoubleTap.size()?-?1;}/***?從事件信息隊(duì)列中移除指定序號(hào)的事件*?*?@param?idx*/private?void?removeEventFromList(int?id){if?(id?>?sEventInfos.size()?||?id?<?0){//?Log.e(MYTAG,?CLASS_NAME?+?".removeEventFromList(),?id="?+?id?+//?",?while?sEventInfos.size()?="?+//?sEventInfos.size());return;}sEventInfos.set(id,?null);}/***?向事件隊(duì)列中添加新信息*?*?@param?e*/private?void?addEventIntoList(EventInfo?info){int?id?=?info.mCurrentDownEvent.getId();if?(id?<?sEventInfos.size()){//?if?(sEventInfos.get(id)?!=?null)//?Log.e(MYTAG,?CLASS_NAME?+?".addEventIntoList,?info("?+?id?+//?")?has?not?set?to?null?!");sEventInfos.set(info.mCurrentDownEvent.getId(),?info);}else?if?(id?==?sEventInfos.size()){sEventInfos.add(info);}else{//?Log.e(MYTAG,?CLASS_NAME?+?".addEventIntoList,?invalidata?id?!");}}public?boolean?onTouchEvent(MotionEvent?ev){if?(mVelocityTracker?==?null){mVelocityTracker?=?VelocityTracker.obtain();}mVelocityTracker.addMovement(ev);//?把所有事件都添加到速度追蹤器,為計(jì)算速度做準(zhǔn)備boolean?handled?=?false;final?int?action?=?ev.getAction();?//?獲取Action//?int?idx?=?(action?&?MotionEvent.ACTION_POINTER_INDEX_MASK)?>>//?MotionEvent.ACTION_POINTER_INDEX_SHIFT;//獲取觸摸事件的序號(hào)int?idx?=?ev.getPointerId(ev.getActionIndex());//?獲取觸摸事件的idswitch?(action?&?MotionEvent.ACTION_MASK){case?MotionEvent.ACTION_DOWN:case?MotionEvent.ACTION_POINTER_DOWN:{EventInfo?info?=?new?EventInfo(MotionEvent.obtain(ev));this.addEventIntoList(info);//?將手勢信息保存到隊(duì)列中if?(mDoubleTapListener?!=?null){//?如果雙擊監(jiān)聽器不為nullif?(mHandler.hasMessages(TAP_DOUBLE)){MultiMotionEvent?e?=?new?MultiMotionEvent(ev);EventInfo?origInfo?=?checkForDoubleTap(e);//?檢查是否構(gòu)成雙擊事件if?(origInfo?!=?null){info.mIsDoubleTapping?=?true;handled?|=?mDoubleTapListener.onDoubleTap(origInfo.mCurrentDownEvent);handled?|=?mDoubleTapListener.onDoubleTapEvent(e);}}if?(!info.mIsDoubleTapping){//?當(dāng)前事件不構(gòu)成雙擊事件,那么發(fā)送延遲消息以判斷onSingleTapConfirmed事件mHandler.sendMessageDelayed(mHandler.obtainMessage(TAP_SINGLE,?idx),?DOUBLE_TAP_TIMEOUT);//?Log.d(MYTAG,?CLASS_NAME?+?":?add?TAP_SINGLE");}}//?記錄X坐標(biāo)和Y坐標(biāo)info.mLastMotionX?=?info.mCurrentDownEvent.getX();info.mLastMotionY?=?info.mCurrentDownEvent.getY();if?(mIsLongpressEnabled){//?允許長按mHandler.removeMessages(LONG_PRESS,?idx);mHandler.sendMessageAtTime(mHandler.obtainMessage(LONG_PRESS,?idx),?info.mCurrentDownEvent.getEventTime()?+?TAP_TIMEOUT?+?LONGPRESS_TIMEOUT);//?延時(shí)消息以觸發(fā)長按手勢//?Log.d(MYTAG,?CLASS_NAME?+//?":add?LONG_PRESS?to?handler??for?idx?"?+?idx);}mHandler.sendMessageAtTime(mHandler.obtainMessage(SHOW_PRESS,?idx),?info.mCurrentDownEvent.getEventTime()?+?TAP_TIMEOUT);//?延時(shí)消息,觸發(fā)showPress手勢handled?|=?mListener.onDown(info.mCurrentDownEvent);//?觸發(fā)onDown()break;}case?MotionEvent.ACTION_UP:case?MotionEvent.ACTION_POINTER_UP:{MultiMotionEvent?currentUpEvent?=?new?MultiMotionEvent(ev);if?(idx?>=?sEventInfos.size()){//?Log.e(MYTAG,?CLASS_NAME?+?":ACTION_POINTER_UP,?idx="?+//?idx?+?",?while?sEventInfos.size()="?+//?sEventInfos.size());break;}EventInfo?info?=?sEventInfos.get(currentUpEvent.getId());if?(info?==?null){//?Log.e(MYTAG,?CLASS_NAME?+?":ACTION_POINTER_UP,?idx="?+//?idx?+?",?Info?=?null");break;}info.mStillDown?=?false;if?(info.mIsDoubleTapping){?//?處于雙擊狀態(tài),則觸發(fā)onDoubleTapEvent事件handled?|=?mDoubleTapListener.onDoubleTapEvent(currentUpEvent);}else?if?(info.mInLongPress){//?處于長按狀態(tài)mHandler.removeMessages(TAP_SINGLE,?idx);//?可以無視這行代碼info.mInLongPress?=?false;}else?if?(info.mAlwaysInTapRegion){//?尚未移動(dòng)過if?(mHandler.hasMessages(TAP_SINGLE,?idx)){//?還在雙擊的時(shí)間閥值內(nèi),所以要為雙擊判斷做額外處理mHandler.removeMessages(TAP_SINGLE,?idx);info.mPreviousUpEvent?=?new?MultiMotionEvent(MotionEvent.obtain(ev));int?index?=?this.addIntoTheMinIndex(info);//?把當(dāng)前事件放入隊(duì)列,等待雙擊的判斷mHandler.sendMessageAtTime(mHandler.obtainMessage(TAP_DOUBLE,?index),?info.mCurrentDownEvent.getEventTime()?+?DOUBLE_TAP_TIMEOUT);?//?將雙擊超時(shí)判斷添加到Handler//?Log.d(MYTAG,?CLASS_NAME?+?":?add?TAP_DOUBLE");}handled?=?mListener.onSingleTapUp(currentUpEvent);//?觸發(fā)onSingleTapUp事件}else{//?A?fling?must?travel?the?minimum?tap?distancefinal?VelocityTracker?velocityTracker?=?mVelocityTracker;velocityTracker.computeCurrentVelocity(1000,?mMaximumFlingVelocity);//?計(jì)算1秒鐘內(nèi)的滑動(dòng)速度//?獲取X和Y方向的速度final?float?velocityX?=?velocityTracker.getXVelocity(idx);final?float?velocityY?=?velocityTracker.getYVelocity(idx);//?Log.i(MYTAG,?CLASS_NAME?+?":ACTION_POINTER_UP,?idx="?+//?idx?+//?",?vx="?+?velocityX?+?",?vy="?+?velocityY);//?觸發(fā)滑動(dòng)事件if?((Math.abs(velocityY)?>?mMinimumFlingVelocity)?||?(Math.abs(velocityX)?>?mMinimumFlingVelocity)){handled?=?mListener.onFling(info.mCurrentDownEvent,?currentUpEvent,?velocityX,?velocityY);}}//?Hold?the?event?we?obtained?above?-?listeners?may?have?changed//?the//?original.if?(action?==?MotionEvent.ACTION_UP){?//?釋放速度追蹤器mVelocityTracker.recycle();mVelocityTracker?=?null;//?Log.w(MYTAG,?CLASS_NAME?+//?":ACTION_POINTER_UP,?mVelocityTracker.recycle()");}info.mIsDoubleTapping?=?false;//?Log.d(MYTAG,?CLASS_NAME?+?"remove?LONG_PRESS");//?移除showPress和長按消息mHandler.removeMessages(SHOW_PRESS,?idx);mHandler.removeMessages(LONG_PRESS,?idx);removeEventFromList(currentUpEvent.getId());//?手指離開,則從隊(duì)列中刪除手勢信息break;}case?MotionEvent.ACTION_MOVE:for?(int?rIdx?=?0;?rIdx?<?ev.getPointerCount();?rIdx++){//?因?yàn)闊o法確定當(dāng)前發(fā)生移動(dòng)的是哪個(gè)手指,所以遍歷處理所有手指MultiMotionEvent?e?=?new?MultiMotionEvent(ev,?rIdx);if?(e.getId()?>=?sEventInfos.size()){//?Log.e(MYTAG,?CLASS_NAME?+?":ACTION_MOVE,?idx="?+?rIdx//?+?",?while?sEventInfos.size()="?+//?sEventInfos.size());break;}EventInfo?info?=?sEventInfos.get(e.getId());if?(info?==?null){//?Log.e(MYTAG,?CLASS_NAME?+?":ACTION_MOVE,?idx="?+?rIdx//?+?",?Info?=?null");break;}if?(info.mInLongPress){?//?長按,則不處理move事件break;}//?當(dāng)前坐標(biāo)float?x?=?e.getX();float?y?=?e.getY();//?距離上次事件移動(dòng)的位置final?float?scrollX?=?x?-?info.mLastMotionX;final?float?scrollY?=?y?-?info.mLastMotionY;if?(info.mIsDoubleTapping){//?雙擊事件handled?|=?mDoubleTapListener.onDoubleTapEvent(e);}else?if?(info.mAlwaysInTapRegion){//?該手勢尚未移動(dòng)過(移動(dòng)的距離小于mTouchSlopSquare,視為未移動(dòng)過)//?計(jì)算從落下到當(dāng)前事件,移動(dòng)的距離final?int?deltaX?=?(int)?(x?-?info.mCurrentDownEvent.getX());final?int?deltaY?=?(int)?(y?-?info.mCurrentDownEvent.getY());//?Log.d(MYTAG,?CLASS_NAME?+?"deltaX="+deltaX+";deltaY="//?+//?deltaX?+"mTouchSlopSquare="?+?mTouchSlopSquare);int?distance?=?(deltaX?*?deltaX)?+?(deltaY?*?deltaY);if?(distance?>?mTouchSlopSquare){?//?移動(dòng)距離超過mTouchSlopSquarehandled?=?mListener.onScroll(info.mCurrentDownEvent,?e,?scrollX,?scrollY);info.mLastMotionX?=?e.getX();info.mLastMotionY?=?e.getY();info.mAlwaysInTapRegion?=?false;//?Log.d(MYTAG,?CLASS_NAME?+//?":remove?LONG_PRESS?for?idx"?+?rIdx?+//?",mTouchSlopSquare("+mTouchSlopSquare+"),?distance("+distance+")");//?清除onSingleTapConform,showPress,longPress三種消息int?id?=?e.getId();mHandler.removeMessages(TAP_SINGLE,?id);mHandler.removeMessages(SHOW_PRESS,?id);mHandler.removeMessages(LONG_PRESS,?id);}if?(distance?>?mBiggerTouchSlopSquare){//?移動(dòng)距離大于mBiggerTouchSlopSquare,則無法構(gòu)成雙擊事件info.mAlwaysInBiggerTapRegion?=?false;}}else?if?((Math.abs(scrollX)?>=?1)?||?(Math.abs(scrollY)?>=?1)){//?之前已經(jīng)移動(dòng)過了handled?=?mListener.onScroll(info.mCurrentDownEvent,?e,?scrollX,?scrollY);info.mLastMotionX?=?x;info.mLastMotionY?=?y;}}break;case?MotionEvent.ACTION_CANCEL:cancel();//?清理}return?handled;}//?清理所有隊(duì)列private?void?cancel(){mHandler.removeMessages(SHOW_PRESS);mHandler.removeMessages(LONG_PRESS);mHandler.removeMessages(TAP_SINGLE);mVelocityTracker.recycle();mVelocityTracker?=?null;sEventInfos.clear();sEventForDoubleTap.clear();} }


參考資料:http://xiaxingwork.iteye.com/blog/1771714

































轉(zhuǎn)載于:https://blog.51cto.com/glblong/1569058

總結(jié)

以上是生活随笔為你收集整理的Android笔记:触摸事件的分析与总结----多点触控的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。