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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

android多点触控的理解

發(fā)布時(shí)間:2023/12/16 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android多点触控的理解 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

首先多點(diǎn)觸控要使用event.getActionMasked()來(lái)獲取事件,調(diào)用情況如下:

  • case MotionEvent.ACTION_DOWN: //第一根手指按下觸發(fā),只會(huì)觸發(fā)一次
  • case MotionEvent.ACTION_MOVE: //所有手指的move事件都會(huì)觸發(fā)這個(gè)事件
  • case MotionEvent.ACTION_UP: //只會(huì)觸發(fā)一次,最后一根手指抬起時(shí)觸發(fā)
  • case MotionEvent.ACTION_POINTER_DOWN: //非第一跟手指按下觸發(fā)
  • case MotionEvent.ACTION_POINTER_UP: //非最后一根手指抬起觸發(fā)
    接下來(lái)看一段代碼和效果
public class MultiTouchView extends View {private float offsetX, offsetY;private float lastOffsetX, lastOffsetY;private float downX, downY;Bitmap bitmap;Paint paint;float currentScale;private int currentPointId;。。。省略@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.test3);paint = new Paint();if ((float) bitmap.getWidth() / bitmap.getHeight() > (float) getWidth() / getHeight()) {//圖片是橫向圖片currentScale = (float) getWidth() / bitmap.getWidth();} else {currentScale = (float) getHeight() / bitmap.getHeight();}}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.translate(offsetX, offsetY);canvas.scale(currentScale, currentScale, getWidth() / 2f, getHeight() / 2f);canvas.drawBitmap(bitmap, (getWidth() - bitmap.getWidth()) / 2f, (getHeight() - bitmap.getHeight()) / 2f, paint);}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getActionMasked()) { //getAction//只會(huì)觸發(fā)一次case MotionEvent.ACTION_DOWN:downX = event.getX();downY = event.getY();currentPointId=0;break;//所有手指移動(dòng)都是觸發(fā)這個(gè)事件case MotionEvent.ACTION_MOVE://獲取id對(duì)應(yīng)的index值,index是會(huì)變化的,id不會(huì)變化//int index= event.findPointerIndex(currentPointId);//移動(dòng)距離:上次偏移值+當(dāng)前滑動(dòng)距離offsetX = lastOffsetX + event.getX() - downX;//event.getY() 使用的是pointerIndexoffsetY = lastOffsetY + event.getY() - downY;invalidate();break;//只會(huì)觸發(fā)一次,最后一根手指抬起時(shí)觸發(fā)case MotionEvent.ACTION_UP://抬手記錄上次偏移值lastOffsetX = offsetX;lastOffsetY = offsetY;break;//非第一跟手指按下觸發(fā)case MotionEvent.ACTION_POINTER_DOWN:break;//非最后一根手指抬起觸發(fā)case MotionEvent.ACTION_POINTER_UP:break;}return true;} }

自定義了一個(gè)view,onDraw繪制了一張圖片,在ACTION_MOVE的時(shí)候offsetX(Y)達(dá)到圖片隨手指滑動(dòng)的效果:

我這里的操作是

  • 先在右上角按下手指1,滑動(dòng),圖片能跟隨手指滑動(dòng)
  • 接著在左下角按下手指2并滑動(dòng)發(fā)現(xiàn)手指2沒(méi)法滑動(dòng)圖片(依舊只會(huì)跟隨手指1滑動(dòng))
  • 然后松開(kāi)手指1,這時(shí)候圖片跳到左下角并能跟隨手指2滑動(dòng)了
  • 最后再按下手指1,圖片跳到了右上角并跟隨手指1滑動(dòng)
  • 為什么第二步按下手指2沒(méi)法滑動(dòng)圖片呢?來(lái)看MotionEvent.ACTION_MOVE中的代碼:

    offsetX = lastOffsetX + event.getX() - downX

    問(wèn)題就在這個(gè)event.getX(),查看MotionEvent 的源碼:

    第二個(gè)參數(shù)pointerIndex用的是默認(rèn)值0,一番查閱后發(fā)現(xiàn):
    每根手指按下后系統(tǒng)都會(huì)保存該手指的index和id,移除一根手指后index會(huì)重新排序,原id不變。當(dāng)插入一個(gè)手指時(shí)會(huì)根據(jù)id列表進(jìn)行插入操作,如 下圖:

    當(dāng)依次按下四根手指時(shí)四根手指的id和index相同,依次是0123,當(dāng)移除第二根手指,那么將會(huì)重新排序,第三根手指的index變?yōu)?,id不變,第四根手指的index變?yōu)?,id不變。這時(shí)候再按下一個(gè)手指它會(huì)發(fā)現(xiàn)id只有0、2、3,于是生成了id為1的手指,然后重新排序變成跟最開(kāi)始的狀態(tài)一樣。

    回頭看之前的操作,依次按下手指1和2時(shí)生成了兩個(gè):手指1(id=0,index=0),手指2(id=1,index=1)
    因此,在上面的操作的第二步中,因?yàn)锳ction_move中event.getX() 始終用的index都是0,所以處理的都是第一根手指,第二根手指自然無(wú)法拉動(dòng)圖片;
    第三步中,因?yàn)橐瞥说谝桓种?#xff0c;進(jìn)行了重新排序,手指2的index變成了0,所以手指2能拖動(dòng)圖片
    第四步,手指1重新按下發(fā)現(xiàn)當(dāng)前只有手指2(id=1),并沒(méi)有id0,因此創(chuàng)建了一個(gè)手指id為0,再重新排序的時(shí)候變成了手指1(id=0,index=0),手指2(id=1,index=1),手指1的index為0,因此是手指1能拖動(dòng)圖片。

    接下來(lái)實(shí)踐一下,將上面的View改為:最后按下的手指拉動(dòng)圖片
    思路:記錄最后按下手指的id,根據(jù)手指的id獲取index,ACTION_MOVE中event.getX/Y()傳入index:

    case MotionEvent.ACTION_DOWN:downX = event.getX();downY = event.getY();currentPointId=0;break;//所有手指移動(dòng)都是觸發(fā)這個(gè)事件 case MotionEvent.ACTION_MOVE://獲取id對(duì)應(yīng)的index值,index是會(huì)變化的,id不會(huì)變化int index= event.findPointerIndex(currentPointId);//根據(jù)id獲取index//移動(dòng)距離:上次偏移值+當(dāng)前滑動(dòng)距離offsetX = lastOffsetX + event.getX(index) - downX;//event.getY() 使用的是pointerIndexoffsetY = lastOffsetY + event.getY(index) - downY;invalidate();break;//只會(huì)觸發(fā)一次,最后一根手指抬起時(shí)觸發(fā)case MotionEvent.ACTION_UP://抬手記錄上次偏移值lastOffsetX = offsetX;lastOffsetY = offsetY;break;//非第一跟手指按下觸發(fā) case MotionEvent.ACTION_POINTER_DOWN:int pointerIndex= event.getActionIndex();currentPointId=event.getPointerId(pointerIndex);//解決跳動(dòng)downX=event.getX(pointerIndex);downY=event.getY(pointerIndex);lastOffsetX = offsetX;lastOffsetY = offsetY;break;

    在ACTION_DOWN時(shí)記錄了當(dāng)前id:currentPointId=0(因?yàn)槭堑谝粋€(gè)手指id必然是0),在ACTION_POINTER_DOWN即非第一根手指按下的時(shí)候通過(guò)getActionIndex、event.getPointerId(pointerIndex)得到按下的id,最后在ACTION_MOVE事件中通過(guò)findPointerIndex(currentPointId)找到當(dāng)前id的index,這樣就保證了index為最后按下的手指index。
    到此就實(shí)現(xiàn)了最后按下的手指拉動(dòng)圖片的效果,但是引入了新的問(wèn)題:當(dāng)拖動(dòng)圖片的那根手指抬起來(lái)后會(huì)出現(xiàn)閃退。
    這是因?yàn)閑vent.findPointerIndex(currentPointId)數(shù)組越界,因?yàn)槭种柑鸷骳urrentPointId被移除了,通過(guò)這個(gè)id找index自然會(huì)報(bào)錯(cuò)。在ACTION_POINTER_UP中進(jìn)行處理:

    //非最后一根手指抬起觸發(fā)case MotionEvent.ACTION_POINTER_UP:int upIndex = event.getActionIndex();int pointerUpId = event.getPointerId(upIndex);if (pointerUpId == currentPointId) {//如果抬起的是最后一個(gè)手指if (upIndex == event.getPointerCount() - 1) {upIndex = event.getPointerCount() - 2;} else {upIndex++;}currentPointId = event.getPointerId(upIndex);//記錄位置,解決跳動(dòng)downX = event.getX(upIndex);downY = event.getY(upIndex);lastOffsetX = offsetX;lastOffsetY = offsetY;}break;

    當(dāng)手指抬起時(shí)獲取手指id,如果id是正在控制拖動(dòng)圖片的手指id,那么如果該id是最后一個(gè)手指則將index回退一個(gè)(將拖動(dòng)交給上一根手指處理),如果該id不是最后一個(gè),那么index++,即交給下一根手指處理。
    最后剩下新手指按下圖片跳動(dòng)的問(wèn)題是因?yàn)槭种赴聪聲r(shí)沒(méi)有記錄當(dāng)前的downX(Y)和lastOffsetX (Y)。
    完整代碼---------------------------------------------------------------------------------------->

    import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View;import androidx.annotation.Nullable;public class MultiTouchView extends View {private float offsetX, offsetY;private float lastOffsetX, lastOffsetY;private float downX, downY;Bitmap bitmap;Paint paint;float currentScale;private int currentPointId;public MultiTouchView(Context context) {this(context, null);}public MultiTouchView(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public MultiTouchView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.test3);paint = new Paint();if ((float) bitmap.getWidth() / bitmap.getHeight() > (float) getWidth() / getHeight()) {//圖片是橫向圖片currentScale = (float) getWidth() / bitmap.getWidth();} else {currentScale = (float) getHeight() / bitmap.getHeight();}}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.translate(offsetX, offsetY);canvas.scale(currentScale, currentScale, getWidth() / 2f, getHeight() / 2f);canvas.drawBitmap(bitmap, (getWidth() - bitmap.getWidth()) / 2f, (getHeight() - bitmap.getHeight()) / 2f, paint);}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getActionMasked()) { //getAction//只會(huì)觸發(fā)一次case MotionEvent.ACTION_DOWN:downX = event.getX();downY = event.getY();currentPointId = 0;break;//所有手指移動(dòng)都是觸發(fā)這個(gè)事件case MotionEvent.ACTION_MOVE://獲取id對(duì)應(yīng)的index值,index是會(huì)變化的,id不會(huì)變化int index = event.findPointerIndex(currentPointId);//根據(jù)id獲取index//移動(dòng)距離:上次偏移值+當(dāng)前滑動(dòng)距離offsetX = lastOffsetX + event.getX(index) - downX;//event.getY() 使用的是pointerIndexoffsetY = lastOffsetY + event.getY(index) - downY;invalidate();break;//只會(huì)觸發(fā)一次,最后一根手指抬起時(shí)觸發(fā)case MotionEvent.ACTION_UP://抬手記錄上次偏移值lastOffsetX = offsetX;lastOffsetY = offsetY;break;//非第一跟手指按下觸發(fā)case MotionEvent.ACTION_POINTER_DOWN:int pointerIndex = event.getActionIndex();currentPointId = event.getPointerId(pointerIndex);//記錄位置,解決跳動(dòng)downX = event.getX(pointerIndex);downY = event.getY(pointerIndex);lastOffsetX = offsetX;lastOffsetY = offsetY;break;//非最后一根手指抬起觸發(fā)case MotionEvent.ACTION_POINTER_UP:int upIndex = event.getActionIndex();int pointerUpId = event.getPointerId(upIndex);if (pointerUpId == currentPointId) {//如果抬起的是最后一個(gè)手指if (upIndex == event.getPointerCount() - 1) {upIndex = event.getPointerCount() - 2;} else {upIndex++;}currentPointId = event.getPointerId(upIndex);//記錄位置,解決跳動(dòng)downX = event.getX(upIndex);downY = event.getY(upIndex);lastOffsetX = offsetX;lastOffsetY = offsetY;}break;}return true;} }

    最終效果:

    總結(jié)

    以上是生活随笔為你收集整理的android多点触控的理解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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