国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android手勢ImageView三部曲 第二部

2019-12-12 03:28:12
字體:
來源:轉載
供稿:網友

廢話不多說了,還記得上一節Android手勢ImageView三部曲(一)最后我們提及的那個框架么?這一節我們重點了掌握一下GestureDetector這個類相關的屬性方法。

一、那么GestureDetector是干嘛的呢?

顧名思義,字面意思就是“手勢檢測器“的意思,還記得我們上一節中實現的GestureImageView么?我們在onTouchEvent中檢測到了各種個樣的手勢(手指按下、抬起、什么時候屬于拖拽、什么時候屬于縮放)都是通過我們的計算得到的,但是有了GestureDetector這個類后,我們不需要自己做判斷現在是什么手勢了,GestureDetector會幫我們做好判斷,完了后通過回調函數告訴你,就像官網所說的(This class should only be used with MotionEvents reported via touch (don't use for trackball events).)這個類僅僅是通過觸碰檢查事件的,而不是用于跟蹤事件的,我檢測到了事件,然后告訴你,至于你需要怎么處理這個事件,那就是你自己的事了。

GestureDetector的一些具體的api大家可以去查看谷歌官方文檔或啟艦大神的博客:

https://developer.android.google.cn/reference/android/view/GestureDetector.html

Android手勢識別器GestureDetector使用詳解

說了這么多估計你都有點累了,下面讓我們看看具體怎么使用:

偷一下懶,我就直接用 Android手勢ImageView三部曲(一)
中的MatrixImageView類改改代碼了:

public class MatrixImageView extends ImageView { private static final int MODE_NONE = 190; private static final int MODE_DRAG = 468; private static final int MODE_ZOOM = 685; private int mode; private float startX, startY; private float midX, midY; private Matrix currMatrix, savedMatrix; private float preRotate, rotate; private float preSpacing; private GestureDetector detector; public MatrixImageView(Context context, AttributeSet attrs) {  super(context, attrs);  initView();  detector=new GestureDetector(context,onGestureListener); } private void initView() {  mode = MODE_NONE;  currMatrix = new Matrix();  savedMatrix = new Matrix();  DisplayMetrics dm = getResources().getDisplayMetrics();  Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.test);  bitmap = Bitmap.createScaledBitmap(bitmap, dm.widthPixels, dm.heightPixels, true);  setImageBitmap(bitmap); } @Override public boolean onTouchEvent(MotionEvent event) {  return detector.onTouchEvent(event); } private GestureDetector.SimpleOnGestureListener onGestureListener=new GestureDetector.SimpleOnGestureListener(){  @Override  public boolean onSingleTapUp(MotionEvent e) {   Log.e("TAG", "====onSingleTapUp=====");   return super.onSingleTapUp(e);  }  @Override  public void onLongPress(MotionEvent e) {   Log.e("TAG", "====onLongPress=====");   super.onLongPress(e);  }  @Override  public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {   Log.e("TAG", "====onScroll=====");   Log.e("TAG", "distanceX===>"+distanceX);   Log.e("TAG", "distanceY===>"+distanceY);   return super.onScroll(e1, e2, distanceX, distanceY);  }  @Override  public void onShowPress(MotionEvent e) {   Log.e("TAG", "====onShowPress=====");   super.onShowPress(e);  }  @Override  public boolean onDown(MotionEvent e) {   Log.e("TAG", "====onDown=====");   return true;  }  @Override  public boolean onDoubleTap(MotionEvent e) {   Log.e("TAG", "====onDoubleTap=====");   return super.onDoubleTap(e);  }  @Override  public boolean onDoubleTapEvent(MotionEvent e) {   Log.e("TAG", "====onDoubleTapEvent=====");   return super.onDoubleTapEvent(e);  }  @Override  public boolean onSingleTapConfirmed(MotionEvent e) {   Log.e("TAG", "====onSingleTapConfirmed=====");   return super.onSingleTapConfirmed(e);  }  @Override  public boolean onContextClick(MotionEvent e) {   Log.e("TAG", "====onContextClick=====");   return super.onContextClick(e);  }  @Override  public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {   Log.e("TAG", "====onFling=====");   Log.e("TAG", "velocityX===>"+velocityX);   Log.e("TAG", "velocityY===>"+velocityY);   return super.onFling(e1, e2, velocityX, velocityY);  } };}

首先我們在構造方法中創建一個手勢監測器的對象GestureDetector:

public MatrixImageView(Context context, AttributeSet attrs) {  super(context, attrs);  initView();  detector=new GestureDetector(context,onGestureListener); }

GestureDetector既然是監聽我們的手勢的工具類,那我們是不是得把我們得手勢交給它呢? 是的!! 于是我們在onTouchEvent中把事件交給GestureDetector:

 @Override public boolean onTouchEvent(MotionEvent event) {  return detector.onTouchEvent(event); }

那我們把事件交給了GestureDetector,GestureDetector處理完畢后我們怎么知道呢? 還記得我們創建GestureDetector對象的時候傳遞的參數嗎?

detector=new GestureDetector(context,onGestureListener);

我們傳遞給了GestureDetector一個onGestureListener對象,GestureDetector檢查完畢手勢后,會調用onGestureListener中的方法進行回調,我們只需要在onGestureListener對象的相應方法中作出處理就可以了:

private GestureDetector.SimpleOnGestureListener onGestureListener=new GestureDetector.SimpleOnGestureListener(){ @Override public boolean onSingleTapUp(MotionEvent e) { Log.e(“TAG”, “====onSingleTapUp=====”); return super.onSingleTapUp(e); } @Override public void onLongPress(MotionEvent e) {  Log.e("TAG", "====onLongPress=====");  super.onLongPress(e); } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {  Log.e("TAG", "====onScroll=====");  Log.e("TAG", "distanceX===>"+distanceX);  Log.e("TAG", "distanceY===>"+distanceY);  return super.onScroll(e1, e2, distanceX, distanceY); } @Override public void onShowPress(MotionEvent e) {  Log.e("TAG", "====onShowPress=====");  super.onShowPress(e); } @Override public boolean onDown(MotionEvent e) {  Log.e("TAG", "====onDown=====");   return super.onDown(e); } @Override public boolean onDoubleTap(MotionEvent e) {  Log.e("TAG", "====onDoubleTap=====");  return super.onDoubleTap(e); } @Override public boolean onDoubleTapEvent(MotionEvent e) {  Log.e("TAG", "====onDoubleTapEvent=====");  return super.onDoubleTapEvent(e); } @Override public boolean onSingleTapConfirmed(MotionEvent e) {  Log.e("TAG", "====onSingleTapConfirmed=====");  return super.onSingleTapConfirmed(e); } @Override public boolean onContextClick(MotionEvent e) {  Log.e("TAG", "====onContextClick=====");  return super.onContextClick(e); } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {  Log.e("TAG", "====onFling=====");  Log.e("TAG", "velocityX===>"+velocityX);  Log.e("TAG", "velocityY===>"+velocityY);  return super.onFling(e1, e2, velocityX, velocityY); }};

我們先不管其中方法啥時候調用,我們先重寫它的所有方法,然后打上log,看看我們手指操作后相應的回調,于是我們運行代碼:

是的,沒錯!就只是一張圖片,因為我們也只是顯示了一張圖片:

我們輕輕的點擊一下屏幕:

03-02 20:47:41.367 1798-1798/com.leo.gestureimageview E/TAG: ====onDown=====
03-02 20:47:41.466 1798-1798/com.leo.gestureimageview E/TAG: ====onShowPress=====
03-02 20:47:41.967 1798-1798/com.leo.gestureimageview E/TAG: ====onLongPress=====

輕輕的點擊一下屏幕:
我們可以看到log執行順序:onDown->onShowPress->onLongPress

我們點擊屏幕按下,然后過一會再放開:

03-02 21:51:27.121 17138-17138/com.leo.gestureimageview E/TAG: ====onDown=====
03-02 21:51:27.222 17138-17138/com.leo.gestureimageview E/TAG: ====onShowPress=====
03-02 21:51:27.722 17138-17138/com.leo.gestureimageview E/TAG: ====onLongPress=====

我們滑動一下手指:

03-02 21:51:27.121 17138-17138/com.leo.gestureimageview E/TAG: ====onDown=====
03-02 21:51:27.222 17138-17138/com.leo.gestureimageview E/TAG: ====onShowPress=====
03-02 21:51:27.722 17138-17138/com.leo.gestureimageview E/TAG: ====onLongPress=====

不管我們怎么樣操作,打印的log總是這三個方法? 這是咋回事呢? 如果看到這里你有疑問的話,那我告訴你,你Android事件傳遞機制掌握的還不是很好,為什么這么說呢?? 下面我們帶著疑問看看源碼:

猜都可以猜到GestureDetector處理手勢的代碼肯定在onTouchEvent方法中,那么我們看一下onTouchEvent方法:

 public boolean onTouchEvent(MotionEvent ev) {  if (mDoubleTapListener != null) {    boolean hadTapMessage = mHandler.hasMessages(TAP);    if (hadTapMessage) mHandler.removeMessages(TAP);    if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) && hadTapMessage &&      isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) {     // This is a second tap     mIsDoubleTapping = true;     // Give a callback with the first tap of the double-tap     handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent);     // Give a callback with down event of the double-tap     handled |= mDoubleTapListener.onDoubleTapEvent(ev);    } else {     // This is a first tap     mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT);    }   }   mDownFocusX = mLastFocusX = focusX;   mDownFocusY = mLastFocusY = focusY;   if (mCurrentDownEvent != null) {    mCurrentDownEvent.recycle();   }   mCurrentDownEvent = MotionEvent.obtain(ev);   mAlwaysInTapRegion = true;   mAlwaysInBiggerTapRegion = true;   mStillDown = true;   mInLongPress = false;   mDeferConfirmSingleTap = false;   if (mIsLongpressEnabled) {    mHandler.removeMessages(LONG_PRESS);    mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime()      + TAP_TIMEOUT + LONGPRESS_TIMEOUT);   }   mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT);   handled |= mListener.onDown(ev);   break; }

代碼太多了,那為什么我們只收到了onDown、onShowPress、onLongPress這三個方法的回調呢?
我們知道,當我們手指剛按下屏幕的時候,ACTION_DOWN會執行,然后我們看到這么一行代碼:

handled |= mListener.onDown(ev);

mListener是我們傳遞的SimpleOnGestureListener,于是就看到了控制臺的第一個log:

03-02 21:51:29.706 17138-17138/com.leo.gestureimageview E/TAG: ====onDown=====

我們的onDown是打印了,然后handled |= mListener.onDown(ev);看一下我們返回的是什么值:

@Override  public boolean onDown(MotionEvent e) {   Log.e("TAG", "====onDown=====");   return super.onDown(e);  }

我們直接返回了super.onDown(e),接著我們看一下父類返回的是什么:

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

可以看到,父類直接返回了false,所以handled此時為false,然后當ACTION_DOWN執行完畢后,就回到了我們的自定義view中的onTouchEvent方法中了:

 @Override public boolean onTouchEvent(MotionEvent event) {  return detector.onTouchEvent(event); }

此時我們的view中的onTouchEvent 方法返回的是false,到了這里懂事件傳遞機制的小伙伴都懂,當我們的onTouchEvent返回了false的話,后面的事件都將接收不到了,也就是說只能執行ACTION_DOWN,那么有些小伙伴可能又要說了,那我把view的clickable或者longclickable設置成true,事件不就可以傳遞了么?
好的~! 我們試一試:

 <com.leo.gestureimageview.MatrixImageView  android:clickable="true"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:scaleType="matrix"  />

運行代碼,還是只打印了那三個方法,那這又是怎么回事呢? 還記得我們view的onTouchEvent方法么?我們是這么寫的:

@Override public boolean onTouchEvent(MotionEvent event) {  return detector.onTouchEvent(event); }

如果改成這樣再試試:

 @Override public boolean onTouchEvent(MotionEvent event) {  detector.onTouchEvent(event);  return super.onTouchEvent(event); }

拖動手指返回結果:

這里寫圖片描述

好啦~!! 終于看到我們久違的結果了,如果我們還是想用以前的寫法,把onTouchEvent的返回結果交給GestureDetector處理該怎么做呢?

@Override public boolean onTouchEvent(MotionEvent event) {  return detector.onTouchEvent(event); }

我們只需要在回調方法的onDown中返回true即可:

 @Override  public boolean onDown(MotionEvent e) {   Log.e("TAG", "====onDown=====");   return true;  }

我們再次運行代碼并拖動手指:

這里寫圖片描述

好啦~! 說了那么多不知道小伙伴們理解了沒?還是不理解的小伙伴可以去看看我前幾篇事件傳遞的博客,嘻嘻~我們還是快點往下走吧….

我們長按一下屏幕然后提起手指:

03-02 22:29:37.361 22104-22104/com.leo.gestureimageview E/TAG: ====onDown=====
03-02 22:29:37.367 22104-22104/com.leo.gestureimageview E/TAG: ====onSingleTapUp=====
03-02 22:29:37.663 22104-22104/com.leo.gestureimageview E/TAG: ====onSingleTapConfirmed=====

執行了onDown=>onSingleTapUp=>onSingleTapConfirmed.

我們快速點擊一下屏幕:

03-02 22:31:48.603 22104-22104/com.leo.gestureimageview E/TAG: ====onDown=====
03-02 22:31:48.610 22104-22104/com.leo.gestureimageview E/TAG: ====onSingleTapUp=====
03-02 22:31:48.903 22104-22104/com.leo.gestureimageview E/TAG: ====onSingleTapConfirmed=====

執行了onDown=>onSingleTapUp=>onSingleTapConfirmed.

然后我們再次滑動手指:

03-02 22:34:41.820 22104-22104/com.leo.gestureimageview E/TAG: ====onDown=====
03-02 22:34:41.920 22104-22104/com.leo.gestureimageview E/TAG: ====onShowPress=====
03-02 22:34:42.018 22104-22104/com.leo.gestureimageview E/TAG: ====onScroll=====
03-02 22:34:42.018 22104-22104/com.leo.gestureimageview E/TAG: distanceX===>-117.13138
03-02 22:34:42.018 22104-22104/com.leo.gestureimageview E/TAG: distanceY===>75.100464
03-02 22:34:42.036 22104-22104/com.leo.gestureimageview E/TAG: ====onScroll=====
03-02 22:34:42.036 22104-22104/com.leo.gestureimageview E/TAG: distanceX===>-75.859314

執行順序:onDown=》onShowPress=》onScroll(很多次)

最后我們手指拖動距離長一點再快一點:

03-02 22:47:42.453 5103-5103/com.leo.gestureimageview E/TAG: distanceX===>-274.69336
03-02 22:47:42.453 5103-5103/com.leo.gestureimageview E/TAG: distanceY===>-0.34838867
03-02 22:47:42.460 5103-5103/com.leo.gestureimageview E/TAG: ====onFling=====
03-02 22:47:42.460 5103-5103/com.leo.gestureimageview E/TAG: velocityX===>27284.943
03-02 22:47:42.460 5103-5103/com.leo.gestureimageview E/TAG: velocityY===>-95.6131

前 面還有一段log沒給出了,調用方法順序為:onDown=》onShowPress=》onScroll(很多次)=》最后松開手指的時候onFling();

好了~! 到這里,我們的回調方法中還有幾個沒有被調用,就是監聽雙擊事件的時候,于是我們雙擊屏幕:

03-02 22:50:34.786 5103-5103/com.leo.gestureimageview E/TAG: ====onDown=====
03-02 22:50:34.793 5103-5103/com.leo.gestureimageview E/TAG: ====onSingleTapUp=====
03-02 22:50:34.924 5103-5103/com.leo.gestureimageview E/TAG: ====onDoubleTap=====
03-02 22:50:34.924 5103-5103/com.leo.gestureimageview E/TAG: ====onDoubleTapEvent=====
03-02 22:50:34.924 5103-5103/com.leo.gestureimageview E/TAG: ====onDown=====
03-02 22:50:34.932 5103-5103/com.leo.gestureimageview E/TAG: ====onDoubleTapEvent=====

我們雙擊屏幕執行的方法為:
onDown=>onSingleTapUp=>onDoubleTap=>onDoubleTapEvent=>onDoubleTapEvent
可見,執行了一次onDoubleTap,兩次onDoubleTapEvent

好啦~! 看完了SimpleOnGestureListener中所有方法的回調,我們反過來再看一遍這些回調方法:

好啦~!說了那么api內容,下面寫個小例子用一下GestureDetector:

package com.leo.gestureimageview;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Matrix;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.util.Log;import android.view.GestureDetector;import android.view.MotionEvent;import android.widget.ImageView;public class MatrixImageView extends ImageView { private Matrix currMatrix; private GestureDetector detector; public MatrixImageView(Context context, AttributeSet attrs) { super(context, attrs); initView(); detector=new GestureDetector(context,onGestureListener); } private void initView() { currMatrix = new Matrix(); DisplayMetrics dm = getResources().getDisplayMetrics(); Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.test); bitmap = Bitmap.createScaledBitmap(bitmap, dm.widthPixels, dm.heightPixels, true); setImageBitmap(bitmap); } @Override public boolean onTouchEvent(MotionEvent event) { return detector.onTouchEvent(event); } private float currX; private float currY; private GestureDetector.SimpleOnGestureListener onGestureListener=new GestureDetector.SimpleOnGestureListener(){ @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {  Log.e("TAG", "====onScroll=====");  Log.e("TAG", "distanceX===>"+distanceX);  Log.e("TAG", "distanceY===>"+distanceY);  currX-=distanceX;  currY-=distanceY;  currMatrix.reset();  currMatrix.postTranslate(currX,currY);  setImageMatrix(currMatrix);  return super.onScroll(e1, e2, distanceX, distanceY); } };}

代碼很短,想必大家都看得懂,就是一個隨著手指移動而移動的圖片:

這里寫圖片描述

好啦~~ 這篇有點長,為什么花這么久去研究GestureDetector,這也是為了給下一節的MoveGestureDetector、RotateGestureDetector、ShoveGestureDetector以及PhotoView這些大牛寫的框架做鋪墊。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 旬阳县| 大埔区| 凌云县| 那坡县| 新郑市| 兰溪市| 库车县| 平谷区| 沁水县| 德令哈市| 惠水县| 剑阁县| 永登县| 石棉县| 万年县| 承德市| 彭山县| 东台市| 姚安县| 永安市| 西林县| 庄浪县| 藁城市| 闵行区| 临颍县| 甘洛县| 灵台县| 行唐县| 建德市| 青岛市| 二连浩特市| 临湘市| 潮州市| 吴川市| 江门市| 丰宁| 桂平市| 孟连| 水城县| 手游| 太和县|