600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > Android笔记:触摸事件的分析与总结----多点触控

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

时间:2021-01-12 14:42:51

相关推荐

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

其他相关博文:

Android笔记:触摸事件的分析与总结----MotionEvent对象

Android笔记:触摸事件的分析与总结----TouchEvent处理机制

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

一、多点触控

当多点同时触摸屏幕时,系统将会产生如下的触摸事件:

1.ACTION_DOWN:触摸屏幕的第一个点。此时手势开始。该点的数据通常在MotionEvent事件队列索引位置0处。

2.ACTION_POINTER_DOWN:除了第一个点的其他触摸点数据。该点的数据的索引位置由getActionIndex()方法返回。

3.ACTION_MOVE:在手势过程中发生的一次变化。

4.ACTION_POINTER_UP:当不是第一个点的其他点UP后触发。

5.ACTION_UP:当手势中的最后一个点离开屏幕。

简单测试范例

布局xml代码如下:

<RelativeLayoutxmlns:android="/apk/res/android"xmlns:tools="/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代码如下:

packagecom.lonshine.d_touchduodian;importandroid.os.Bundle;importandroid.app.Activity;importandroid.util.Log;importandroid.view.MotionEvent;importandroid.view.View;importandroid.view.View.OnTouchListener;importandroid.widget.RelativeLayout;publicclassMainActivityextendsActivityimplementsOnTouchListener{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);RelativeLayoutlayout=(RelativeLayout)findViewById(R.id.layout1);layout.setOnTouchListener(this);}@OverridepublicbooleanonTouch(Viewv,MotionEventevent){Stringtag=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))){returntrue;}else{returnfalse;}}protectedstaticStringdescribeEvent(MotionEventevent){StringBuildersb=newStringBuilder(500);sb.append("Action:").append(event.getAction()).append("\n");//获取触控动作比如ACTION_DOWNintcount=event.getPointerCount();sb.append("触点个数:").append(count).append("\n");inti=0;while(i<count){sb.append("-------------------------").append("\n");intpointerId=event.getPointerId(i);sb.append("触点序号:").append(i).append("\n");sb.append("触点ID:").append(pointerId).append("\n");sb.append("相对坐标:").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("按下时间:").append(event.getDownTime()).append("ms");sb.append("结束时间:").append(event.getEventTime()).append("ms");sb.append("运行时间:").append(event.getEventTime()-event.getDownTime()).append("ms\n");returnsb.toString();}privatevoidlogAction(MotionEventevent){intmasked=event.getActionMasked();intindex=event.getActionIndex();intpointerId=event.getPointerId(index);if(masked==5||masked==6){masked=masked-5;}Log.e("Action","触点序号:"+index);Log.e("Action","触点ID:"+pointerId);Log.e("Action","ActionMasked:"+masked);}}

多点触控的日志打印出来太多,此处仅针对日志输出作简单分析:

A.按下第一根手指时,获得一个索引为0且指针ID为0的指针(ACTION_DOWN = 0);

B.接下去action输出为2(ACTION_MOVE),此时仍然仅有一个指针,并且索引和ID都为0;

C.然后按下第二根手指,action值输出为261。此值由两部分组成:一个是指针索引,一个是指针正在执行何种操作;

D.将十进制261转换为十六进制数为0x00000105。其中01代表指针索引,05代表操作值(即ACTION_POINTER_DOWN的值,用于多点触摸场景);

E.依此类推,当按下第三根手指时action输出值为0x00000205(十进制517),第四根则为0x000305(十进制773);

F.当第一根手指离开屏幕时,action值为0x00000006(十进制6),即索引为0,操作值为6(即ACTION_POINTER_UP);

G.如果此时第二根手指离开时,action值应该为0x00000106(十进制262),因为此时仍然拥有两根手指的信息;

H.而实际结果并没有得到262的action值,这是因为当第一根手指离开屏幕后,第二根手指的索引从1更改成了0,但是指针ID仍然为1.

I.对于每一次移动,action值将始终为2,因为ACTION_MOVE事件并没有包含哪根手指在移动的信息。

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

其他小结:

(1)getPointerCount() 获得触屏的点数,

getActionIndex()获得触点的指针索引,

getPointerId(index)获得指针索引对应的触点ID;

(2)getActionMasked()表示用于多点触控检测点。而在1.6和2.1中并没有event.getActionMasked()这个方法,其实他就是把event.getAction()& MotionEvent.ACTION_MASK封装了一下。

二、其他参考范例:

(一)单点触摸拖动图片与多点触摸缩放图片

packagecom.lonshine.touchdemo;importandroid.app.Activity;importandroid.content.Context;importandroid.graphics.*;importandroid.graphics.drawable.BitmapDrawable;importandroid.os.Bundle;importandroid.view.MotionEvent;importandroid.widget.ImageView;importandroid.widget.ImageView.ScaleType;/***多点触控来控制ImageView中图像的放大与缩小,单点触控则用来拖动图片**@authorzeng**/publicclassMainActivityextendsActivity{privateMyImageViewp_w_picpathView;privateBitmapbitmap;//两点触屏后之间的长度privatefloatbeforeLenght;privatefloatafterLenght;//单点移动的前后坐标值privatefloatafterX,afterY;privatefloatbeforeX,beforeY;/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);findView();setContentView(p_w_picpathView);config();}privatevoidfindView(){p_w_picpathView=newMyImageView(this);//获得图片bitmap=((BitmapDrawable)getResources().getDrawable(R.drawable.xing)).getBitmap();}privatevoidconfig(){//设置p_w_picpathView的显示图片p_w_picpathView.setImageBitmap(bitmap);//设置图片填充ImageViewp_w_picpathView.setScaleType(ScaleType.FIT_XY);}//创建一个自己的ImageView类classMyImageViewextendsImageView{privatefloatscale=0.1f;publicMyImageView(Contextcontext){super(context);}//用来设置ImageView的位置privatevoidsetLocation(intx,inty){this.setFrame(this.getLeft()+x,this.getTop()+y,this.getRight()+x,this.getBottom()+y);}/***用来放大缩小ImageView因为图片是填充ImageView的,所以也就有放大缩小图片的效果flag为0是放大图片,为1是缩小图片*/privatevoidsetScale(floattemp,intflag){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()));}}//绘制边框@OverrideprotectedvoidonDraw(Canvascanvas){super.onDraw(canvas);Rectrec=canvas.getClipBounds();rec.bottom--;rec.right--;Paintpaint=newPaint();paint.setColor(Color.RED);paint.setStyle(Paint.Style.STROKE);canvas.drawRect(rec,paint);}/***让图片跟随手指触屏的位置移动beforeX、Y是用来保存前一位置的坐标afterX、Y是用来保存当前位置的坐标*它们的差值就是ImageView各坐标的增加或减少值*/publicvoidmoveWithFinger(MotionEventevent){switch(event.getAction()){caseMotionEvent.ACTION_DOWN:beforeX=event.getX();beforeY=event.getY();break;caseMotionEvent.ACTION_MOVE:afterX=event.getX();afterY=event.getY();this.setLocation((int)(afterX-beforeX),(int)(afterY-beforeY));beforeX=afterX;beforeY=afterY;break;caseMotionEvent.ACTION_UP:break;}}/***通过多点触屏放大或缩小图像beforeLenght用来保存前一时间两点之间的距离afterLenght用来保存当前时间两点之间的距离*/publicvoidscaleWithFinger(MotionEventevent){floatmoveX=event.getX(1)-event.getX(0);floatmoveY=event.getY(1)-event.getY(0);switch(event.getAction()){caseMotionEvent.ACTION_DOWN:beforeLenght=(float)Math.sqrt((moveX*moveX)+(moveY*moveY));break;caseMotionEvent.ACTION_MOVE://得到两个点之间的长度afterLenght=(float)Math.sqrt((moveX*moveX)+(moveY*moveY));floatgapLenght=afterLenght-beforeLenght;if(gapLenght==0){break;}//如果当前时间两点距离大于前一时间两点距离,则传0,否则传1if(gapLenght>0){this.setScale(scale,0);}else{this.setScale(scale,1);}beforeLenght=afterLenght;break;}}}//这里来监听屏幕触控时间@OverridepublicbooleanonTouchEvent(MotionEventevent){/***判定用户是否触摸到了图片如果是单点触摸则调用控制图片移动的方法如果是2点触控则调用控制图片大小的方法*/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);}elseif(event.getPointerCount()==1){p_w_picpathView.moveWithFinger(event);}}returntrue;}}

范例参考自:/ldj299/article/details/6422547

(二)实现多点消息拦截,用于多个物体拖动等效果

packagecom.lonshine.d_touchdemo;importjava.util.ArrayList;importjava.util.List;importandroid.content.Context;importandroid.os.Handler;importandroid.os.Message;importandroid.view.MotionEvent;importandroid.view.VelocityTracker;importandroid.view.ViewConfiguration;/***实现多点消息拦截,用于多个物体拖动等效果*@authorzeng*/publicclassMultiTouchGestureDetector{@SuppressWarnings("unused")privatestaticfinalStringMYTAG="Alan";publicstaticfinalStringCLASS_NAME="MultiTouchGestureDetector";/***事件信息类<br/>*用来记录一个手势*/privateclassEventInfo{privateMultiMotionEventmCurrentDownEvent;//当前的down事件privateMultiMotionEventmPreviousUpEvent;//上一次up事件privatebooleanmStillDown;//当前手指是否还在屏幕上privatebooleanmInLongPress;//当前事件是否属于长按手势privatebooleanmAlwaysInTapRegion;//是否当前手指仅在小范围内移动,当手指仅在小范围内移动时,视为手指未曾移动过,不会触发onScroll手势privatebooleanmAlwaysInBiggerTapRegion;//是否当前手指在较大范围内移动,仅当此值为true时,双击手势才能成立privatebooleanmIsDoubleTapping;//当前手势,是否为双击手势privatefloatmLastMotionY;//最后一次事件的X坐标privatefloatmLastMotionX;//最后一次事件的Y坐标privateEventInfo(MotionEvente){this(newMultiMotionEvent(e));}privateEventInfo(MultiMotionEventme){mCurrentDownEvent=me;mStillDown=true;mInLongPress=false;mAlwaysInTapRegion=true;mAlwaysInBiggerTapRegion=true;mIsDoubleTapping=false;}//释放MotionEven对象,使系统能够继续使用它们publicvoidrecycle(){if(mCurrentDownEvent!=null){mCurrentDownEvent.recycle();mCurrentDownEvent=null;}if(mPreviousUpEvent!=null){mPreviousUpEvent.recycle();mPreviousUpEvent=null;}}@Overridepublicvoidfinalize(){this.recycle();}}/***多点事件类<br/>*将一个多点事件拆分为多个单点事件,并方便获得事件的绝对坐标<br/>*绝对坐标用以在界面中找到触点所在的控件**@authorray-ni*/publicclassMultiMotionEvent{privateMotionEventmEvent;privateintmIndex;privateMultiMotionEvent(MotionEvente){mEvent=e;mIndex=(e.getAction()&MotionEvent.ACTION_POINTER_ID_MASK)>>MotionEvent.ACTION_POINTER_ID_SHIFT;//等效于//mEvent.getActionIndex();}privateMultiMotionEvent(MotionEvente,intidx){mEvent=e;mIndex=idx;}//行为publicintgetAction(){intaction=mEvent.getAction()&MotionEvent.ACTION_MASK;//等效于//mEvent.getActionMasked();switch(action){caseMotionEvent.ACTION_POINTER_DOWN:action=MotionEvent.ACTION_DOWN;break;caseMotionEvent.ACTION_POINTER_UP:action=MotionEvent.ACTION_UP;break;}returnaction;}//返回X的绝对坐标publicfloatgetX(){returnmEvent.getX(mIndex)+mEvent.getRawX()-mEvent.getX();}//返回Y的绝对坐标publicfloatgetY(){returnmEvent.getY(mIndex)+mEvent.getRawY()-mEvent.getY();}//事件发生的时间publiclonggetEventTime(){returnmEvent.getEventTime();}//事件序号publicintgetIndex(){returnmIndex;}//事件IDpublicintgetId(){returnmEvent.getPointerId(mIndex);}//释放事件对象,使系统能够继续使用publicvoidrecycle(){if(mEvent!=null){mEvent.recycle();mEvent=null;}}}//多点手势监听器publicinterfaceMultiTouchGestureListener{//手指触碰到屏幕,由一个ACTION_DOWN触发booleanonDown(MultiMotionEvente);//确定一个press事件,强调手指按下的一段时间(TAP_TIMEOUT)内,手指未曾移动或抬起voidonShowPress(MultiMotionEvente);//手指点击屏幕后离开,由ACTION_UP引发,可以简单的理解为单击事件,即手指点击时间不长(未构成长按事件),也不曾移动过booleanonSingleTapUp(MultiMotionEvente);//长按,手指点下后一段时间(DOUBLE_TAP_TIMEOUT)内,不曾抬起或移动voidonLongPress(MultiMotionEvente);//拖动,由ACTION_MOVE触发,手指地按下后,在屏幕上移动booleanonScroll(MultiMotionEvente1,MultiMotionEvente2,floatdistanceX,floatdistanceY);//滑动,由ACTION_UP触发,手指按下并移动一段距离后,抬起时触发booleanonFling(MultiMotionEvente1,MultiMotionEvente2,floatvelocityX,floatvelocityY);}//多点双击监听器publicinterfaceMultiTouchDoubleTapListener{//单击事件确认,强调第一个单击事件发生后,一段时间内,未发生第二次单击事件,即确定不会触发双击事件booleanonSingleTapConfirmed(MultiMotionEvente);//双击事件,//由ACTION_DOWN触发,从第一次单击事件的DOWN事件开始的一段时间(DOUBLE_TAP_TIMEOUT)内结束(即手指),//并且在第一次单击事件的UP时间开始后的一段时间内(DOUBLE_TAP_TIMEOUT)发生第二次单击事件,//除此之外两者坐标间距小于定值(DOUBLE_TAP_SLAP)时,则触发双击事件booleanonDoubleTap(MultiMotionEvente);//双击事件,与onDoubleTap事件不同之处在于,构成双击的第二次点击的ACTION_DOWN,ACTION_MOVE和ACTION_UP都会触发该事件booleanonDoubleTapEvent(MultiMotionEvente);}//事件信息队列,队列的下标与MotionEvent的pointId对应privatestaticList<EventInfo>sEventInfos=newArrayList<EventInfo>(10);//双击判断队列,这个队列中的元素等待双击超时的判断结果privatestaticList<EventInfo>sEventForDoubleTap=newArrayList<EventInfo>(5);//指定大点击区域的大小(这个比较拗口),这个值主要用于帮助判断双击是否成立privateintmBiggerTouchSlopSquare=20*20;//判断是否构成onScroll手势,当手指在这个范围内移动时,不触发onScroll手势privateintmTouchSlopSquare;//判断是否构成双击,只有两次点击的距离小于该值,才能构成双击手势privateintmDoubleTapSlopSquare;//最小滑动速度privateintmMinimumFlingVelocity;//最大滑动速度privateintmMaximumFlingVelocity;//长按阀值,当手指按下后,在该阀值的时间内,未移动超过mTouchSlopSquare的距离并未抬起,则长按手势触发privatestaticfinalintLONGPRESS_TIMEOUT=ViewConfiguration.getLongPressTimeout();//showPress手势的触发阀值,当手指按下后,在该阀值的时间内,未移动超过mTouchSlopSquare的距离并未抬起,则showPress手势触发privatestaticfinalintTAP_TIMEOUT=ViewConfiguration.getTapTimeout();//双击超时阀值,仅在两次双击事件的间隔(第一次单击的UP事件和第二次单击的DOWN事件)小于此阀值,双击事件才能成立privatestaticfinalintDOUBLE_TAP_TIMEOUT=ViewConfiguration.getDoubleTapTimeout();//双击区域阀值,仅在两次双击事件的距离小于此阀值,双击事件才能成立privatestaticfinalintDOUBLE_TAP_SLAP=64;//GestureHandler所处理的Message的what属性可能为以下常量://showPress手势privatestaticfinalintSHOW_PRESS=1;//长按手势privatestaticfinalintLONG_PRESS=2;//SingleTapConfirmed手势privatestaticfinalintTAP_SINGLE=3;//双击手势privatestaticfinalintTAP_DOUBLE=4;//手势处理器privatefinalGestureHandlermHandler;//手势监听器privatefinalMultiTouchGestureListenermListener;//双击监听器privateMultiTouchDoubleTapListenermDoubleTapListener;//长按允许阀值privatebooleanmIsLongpressEnabled;//速度追踪器privateVelocityTrackermVelocityTracker;privateclassGestureHandlerextendsHandler{GestureHandler(){super();}GestureHandler(Handlerhandler){super(handler.getLooper());}@OverridepublicvoidhandleMessage(Messagemsg){intidx=(Integer)msg.obj;switch(msg.what){caseSHOW_PRESS:{if(idx>=sEventInfos.size()){//Log.w(MYTAG,CLASS_NAME+//":handleMessage,msg.what=SHOW_PRESS,idx="+idx+//",whilesEventInfos.size()="//+sEventInfos.size());break;}EventInfoinfo=sEventInfos.get(idx);if(info==null){//Log.e(MYTAG,CLASS_NAME+//":handleMessage,msg.what=SHOW_PRESS,idx="+idx+//",Info=null");break;}//触发手势监听器的onShowPress事件mListener.onShowPress(info.mCurrentDownEvent);break;}caseLONG_PRESS:{//Log.d(MYTAG,CLASS_NAME+":triggerLONG_PRESS");if(idx>=sEventInfos.size()){//Log.w(MYTAG,CLASS_NAME+//":handleMessage,msg.what=LONG_PRESS,idx="+idx+//",whilesEventInfos.size()="//+sEventInfos.size());break;}EventInfoinfo=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;}caseTAP_SINGLE:{//Log.d(MYTAG,CLASS_NAME+":trrigerTAP_SINGLE");//Iftheuser'sfingerisstilldown,donotcountitasa//tapif(idx>=sEventInfos.size()){//Log.e(MYTAG,CLASS_NAME+//":handleMessage,msg.what=TAP_SINGLE,idx="+idx+//",whilesEventInfos.size()="//+sEventInfos.size());break;}EventInfoinfo=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){//手指在双击超时的阀值内未离开屏幕进行第二次单击事件,则确定单击事件成立(不再触发双击事件)mDoubleTapListener.onSingleTapConfirmed(info.mCurrentDownEvent);}break;}caseTAP_DOUBLE:{if(idx>=sEventForDoubleTap.size()){//Log.w(MYTAG,CLASS_NAME+//":handleMessage,msg.what=TAP_DOUBLE,idx="+idx+//",whilesEventForDoubleTap.size()="//+sEventForDoubleTap.size());break;}EventInfoinfo=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);//这个没什么好做的,就是把队列中对应的元素清除而已break;}default:thrownewRuntimeException("Unknownmessage"+msg);//never}}}/***触发长按事件**@paraminfo*@paramidx*/privatevoiddispatchLongPress(EventInfoinfo,intidx){mHandler.removeMessages(TAP_SINGLE,idx);//移除单击事件确认info.mInLongPress=true;mListener.onLongPress(info.mCurrentDownEvent);}/***构造器1**@paramcontext*@paramlistener*/publicMultiTouchGestureDetector(Contextcontext,MultiTouchGestureListenerlistener){this(context,listener,null);}/***构造器2**@paramcontext*@paramlistener*@paramhandler*/publicMultiTouchGestureDetector(Contextcontext,MultiTouchGestureListenerlistener,Handlerhandler){if(handler!=null){mHandler=newGestureHandler(handler);}else{mHandler=newGestureHandler();}mListener=listener;if(listenerinstanceofMultiTouchDoubleTapListener){setOnDoubleTapListener((MultiTouchDoubleTapListener)listener);}init(context);}/***初始化识别器**@paramcontext*/privatevoidinit(Contextcontext){if(mListener==null){thrownewNullPointerException("OnGestureListenermustnotbenull");}mIsLongpressEnabled=true;inttouchSlop,doubleTapSlop;if(context==null){touchSlop=ViewConfiguration.getTouchSlop();doubleTapSlop=DOUBLE_TAP_SLAP;mMinimumFlingVelocity=ViewConfiguration.getMinimumFlingVelocity();mMaximumFlingVelocity=ViewConfiguration.getMaximumFlingVelocity();}else{//允许识别器在App中,使用偏好的设定finalViewConfigurationconfiguration=ViewConfiguration.get(context);touchSlop=configuration.getScaledTouchSlop();doubleTapSlop=configuration.getScaledDoubleTapSlop();mMinimumFlingVelocity=configuration.getScaledMinimumFlingVelocity();mMaximumFlingVelocity=configuration.getScaledMaximumFlingVelocity();}mTouchSlopSquare=touchSlop*touchSlop/16;mDoubleTapSlopSquare=doubleTapSlop*doubleTapSlop;}/***设置双击监听器**@paramonDoubleTapListener*/publicvoidsetOnDoubleTapListener(MultiTouchDoubleTapListeneronDoubleTapListener){mDoubleTapListener=onDoubleTapListener;}/***设置是否允许长按**@paramisLongpressEnabled*/publicvoidsetIsLongpressEnabled(booleanisLongpressEnabled){mIsLongpressEnabled=isLongpressEnabled;}/***判断是否允许长按**@return*/publicbooleanisLongpressEnabled(){returnmIsLongpressEnabled;}/***判断当前事件是否为双击事件<br/>*通过遍历sEventForDoubleTap来匹配是否存在能够构成双击事件的单击事件**@parame*@return*/privateEventInfocheckForDoubleTap(MultiMotionEvente){if(sEventForDoubleTap.isEmpty()){//Log.e(MYTAG,CLASS_NAME+//":checkForDoubleTap(),sEventForDoubleTapisempty!");returnnull;}for(inti=0;i<sEventForDoubleTap.size();i++){EventInfoinfo=sEventForDoubleTap.get(i);if(info!=null&&isConsideredDoubleTap(info,e)){sEventForDoubleTap.set(i,null);//这个单击事件已经被消耗了,所以置为nullmHandler.removeMessages(TAP_DOUBLE,i);//移除Handler内的为处理消息returninfo;}}returnnull;}/***判断当前按下事件是否能和指定的单击事件构成双击事件**@paraminfo*@paramsecondDown*@return*/privatebooleanisConsideredDoubleTap(EventInfoinfo,MultiMotionEventsecondDown){if(!info.mAlwaysInBiggerTapRegion){//如多第一次单击事件有过较大距离的移动,则无法构成双击事件returnfalse;}if(secondDown.getEventTime()-info.mPreviousUpEvent.getEventTime()>DOUBLE_TAP_TIMEOUT){//如果第一次单击的UP时间和第二次单击的down时间时间间隔大于DOUBLE_TAP_TIMEOUT,也无法构成双击事件returnfalse;}intdeltaX=(int)info.mCurrentDownEvent.getX()-(int)secondDown.getX();intdeltaY=(int)info.mCurrentDownEvent.getY()-(int)secondDown.getY();return(deltaX*deltaX+deltaY*deltaY<mDoubleTapSlopSquare);//最后判断两次单击事件的距离}/***将事件信息放入双击判断队列,并返回序号**@paraminfo*@return*/privateintaddIntoTheMinIndex(EventInfoinfo){for(inti=0;i<sEventForDoubleTap.size();i++){if(sEventForDoubleTap.get(i)==null){sEventForDoubleTap.set(i,info);returni;}}sEventForDoubleTap.add(info);returnsEventForDoubleTap.size()-1;}/***从事件信息队列中移除指定序号的事件**@paramidx*/privatevoidremoveEventFromList(intid){if(id>sEventInfos.size()||id<0){//Log.e(MYTAG,CLASS_NAME+".removeEventFromList(),id="+id+//",whilesEventInfos.size()="+//sEventInfos.size());return;}sEventInfos.set(id,null);}/***向事件队列中添加新信息**@parame*/privatevoidaddEventIntoList(EventInfoinfo){intid=info.mCurrentDownEvent.getId();if(id<sEventInfos.size()){//if(sEventInfos.get(id)!=null)//Log.e(MYTAG,CLASS_NAME+".addEventIntoList,info("+id+//")hasnotsettonull!");sEventInfos.set(info.mCurrentDownEvent.getId(),info);}elseif(id==sEventInfos.size()){sEventInfos.add(info);}else{//Log.e(MYTAG,CLASS_NAME+".addEventIntoList,invalidataid!");}}publicbooleanonTouchEvent(MotionEventev){if(mVelocityTracker==null){mVelocityTracker=VelocityTracker.obtain();}mVelocityTracker.addMovement(ev);//把所有事件都添加到速度追踪器,为计算速度做准备booleanhandled=false;finalintaction=ev.getAction();//获取Action//intidx=(action&MotionEvent.ACTION_POINTER_INDEX_MASK)>>//MotionEvent.ACTION_POINTER_INDEX_SHIFT;//获取触摸事件的序号intidx=ev.getPointerId(ev.getActionIndex());//获取触摸事件的idswitch(action&MotionEvent.ACTION_MASK){caseMotionEvent.ACTION_DOWN:caseMotionEvent.ACTION_POINTER_DOWN:{EventInfoinfo=newEventInfo(MotionEvent.obtain(ev));this.addEventIntoList(info);//将手势信息保存到队列中if(mDoubleTapListener!=null){//如果双击监听器不为nullif(mHandler.hasMessages(TAP_DOUBLE)){MultiMotionEvente=newMultiMotionEvent(ev);EventInfoorigInfo=checkForDoubleTap(e);//检查是否构成双击事件if(origInfo!=null){info.mIsDoubleTapping=true;handled|=mDoubleTapListener.onDoubleTap(origInfo.mCurrentDownEvent);handled|=mDoubleTapListener.onDoubleTapEvent(e);}}if(!info.mIsDoubleTapping){//当前事件不构成双击事件,那么发送延迟消息以判断onSingleTapConfirmed事件mHandler.sendMessageDelayed(mHandler.obtainMessage(TAP_SINGLE,idx),DOUBLE_TAP_TIMEOUT);//Log.d(MYTAG,CLASS_NAME+":addTAP_SINGLE");}}//记录X坐标和Y坐标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);//延时消息以触发长按手势//Log.d(MYTAG,CLASS_NAME+//":addLONG_PRESStohandlerforidx"+idx);}mHandler.sendMessageAtTime(mHandler.obtainMessage(SHOW_PRESS,idx),info.mCurrentDownEvent.getEventTime()+TAP_TIMEOUT);//延时消息,触发showPress手势handled|=mListener.onDown(info.mCurrentDownEvent);//触发onDown()break;}caseMotionEvent.ACTION_UP:caseMotionEvent.ACTION_POINTER_UP:{MultiMotionEventcurrentUpEvent=newMultiMotionEvent(ev);if(idx>=sEventInfos.size()){//Log.e(MYTAG,CLASS_NAME+":ACTION_POINTER_UP,idx="+//idx+",whilesEventInfos.size()="+//sEventInfos.size());break;}EventInfoinfo=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){//处于双击状态,则触发onDoubleTapEvent事件handled|=mDoubleTapListener.onDoubleTapEvent(currentUpEvent);}elseif(info.mInLongPress){//处于长按状态mHandler.removeMessages(TAP_SINGLE,idx);//可以无视这行代码info.mInLongPress=false;}elseif(info.mAlwaysInTapRegion){//尚未移动过if(mHandler.hasMessages(TAP_SINGLE,idx)){//还在双击的时间阀值内,所以要为双击判断做额外处理mHandler.removeMessages(TAP_SINGLE,idx);info.mPreviousUpEvent=newMultiMotionEvent(MotionEvent.obtain(ev));intindex=this.addIntoTheMinIndex(info);//把当前事件放入队列,等待双击的判断mHandler.sendMessageAtTime(mHandler.obtainMessage(TAP_DOUBLE,index),info.mCurrentDownEvent.getEventTime()+DOUBLE_TAP_TIMEOUT);//将双击超时判断添加到Handler//Log.d(MYTAG,CLASS_NAME+":addTAP_DOUBLE");}handled=mListener.onSingleTapUp(currentUpEvent);//触发onSingleTapUp事件}else{//AflingmusttraveltheminimumtapdistancefinalVelocityTrackervelocityTracker=mVelocityTracker;puteCurrentVelocity(1000,mMaximumFlingVelocity);//计算1秒钟内的滑动速度//获取X和Y方向的速度finalfloatvelocityX=velocityTracker.getXVelocity(idx);finalfloatvelocityY=velocityTracker.getYVelocity(idx);//Log.i(MYTAG,CLASS_NAME+":ACTION_POINTER_UP,idx="+//idx+//",vx="+velocityX+",vy="+velocityY);//触发滑动事件if((Math.abs(velocityY)>mMinimumFlingVelocity)||(Math.abs(velocityX)>mMinimumFlingVelocity)){handled=mListener.onFling(info.mCurrentDownEvent,currentUpEvent,velocityX,velocityY);}}//Holdtheeventweobtainedabove-listenersmayhavechanged//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+"removeLONG_PRESS");//移除showPress和长按消息mHandler.removeMessages(SHOW_PRESS,idx);mHandler.removeMessages(LONG_PRESS,idx);removeEventFromList(currentUpEvent.getId());//手指离开,则从队列中删除手势信息break;}caseMotionEvent.ACTION_MOVE:for(intrIdx=0;rIdx<ev.getPointerCount();rIdx++){//因为无法确定当前发生移动的是哪个手指,所以遍历处理所有手指MultiMotionEvente=newMultiMotionEvent(ev,rIdx);if(e.getId()>=sEventInfos.size()){//Log.e(MYTAG,CLASS_NAME+":ACTION_MOVE,idx="+rIdx//+",whilesEventInfos.size()="+//sEventInfos.size());break;}EventInfoinfo=sEventInfos.get(e.getId());if(info==null){//Log.e(MYTAG,CLASS_NAME+":ACTION_MOVE,idx="+rIdx//+",Info=null");break;}if(info.mInLongPress){//长按,则不处理move事件break;}//当前坐标floatx=e.getX();floaty=e.getY();//距离上次事件移动的位置finalfloatscrollX=x-info.mLastMotionX;finalfloatscrollY=y-info.mLastMotionY;if(info.mIsDoubleTapping){//双击事件handled|=mDoubleTapListener.onDoubleTapEvent(e);}elseif(info.mAlwaysInTapRegion){//该手势尚未移动过(移动的距离小于mTouchSlopSquare,视为未移动过)//计算从落下到当前事件,移动的距离finalintdeltaX=(int)(x-info.mCurrentDownEvent.getX());finalintdeltaY=(int)(y-info.mCurrentDownEvent.getY());//Log.d(MYTAG,CLASS_NAME+"deltaX="+deltaX+";deltaY="//+//deltaX+"mTouchSlopSquare="+mTouchSlopSquare);intdistance=(deltaX*deltaX)+(deltaY*deltaY);if(distance>mTouchSlopSquare){//移动距离超过mTouchSlopSquarehandled=mListener.onScroll(info.mCurrentDownEvent,e,scrollX,scrollY);info.mLastMotionX=e.getX();info.mLastMotionY=e.getY();info.mAlwaysInTapRegion=false;//Log.d(MYTAG,CLASS_NAME+//":removeLONG_PRESSforidx"+rIdx+//",mTouchSlopSquare("+mTouchSlopSquare+"),distance("+distance+")");//清除onSingleTapConform,showPress,longPress三种消息intid=e.getId();mHandler.removeMessages(TAP_SINGLE,id);mHandler.removeMessages(SHOW_PRESS,id);mHandler.removeMessages(LONG_PRESS,id);}if(distance>mBiggerTouchSlopSquare){//移动距离大于mBiggerTouchSlopSquare,则无法构成双击事件info.mAlwaysInBiggerTapRegion=false;}}elseif((Math.abs(scrollX)>=1)||(Math.abs(scrollY)>=1)){//之前已经移动过了handled=mListener.onScroll(info.mCurrentDownEvent,e,scrollX,scrollY);info.mLastMotionX=x;info.mLastMotionY=y;}}break;caseMotionEvent.ACTION_CANCEL:cancel();//清理}returnhandled;}//清理所有队列privatevoidcancel(){mHandler.removeMessages(SHOW_PRESS);mHandler.removeMessages(LONG_PRESS);mHandler.removeMessages(TAP_SINGLE);mVelocityTracker.recycle();mVelocityTracker=null;sEventInfos.clear();sEventForDoubleTap.clear();}}

参考资料:/blog/1771714

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。