Android VersionedGestureDetector手势事件

  今天研究了一下PhotoView,发现里面的自定义的手势事件可以支持所有的SDK版本,该事件可以实现拖拽、滑动、缩放功能。下面直接上代码:

  1 public abstract class VersionedGestureDetector {
  2     static final String LOG_TAG = "VersionedGestureDetector";
  3     OnGestureListener mListener;
  4 
  5     public static VersionedGestureDetector newInstance(Context context, OnGestureListener listener) {
  6         final int sdkVersion = Build.VERSION.SDK_INT;
  7         VersionedGestureDetector detector = null;
  8         if (sdkVersion < Build.VERSION_CODES.ECLAIR) {
  9             detector = new CupcakeDetector(context);
 10         } else if (sdkVersion < Build.VERSION_CODES.FROYO) {
 11             detector = new EclairDetector(context);
 12         } else {
 13             detector = new FroyoDetector(context);
 14         }
 15 
 16         detector.mListener = listener;
 17 
 18         return detector;
 19     }
 20 
 21     public abstract boolean onTouchEvent(MotionEvent ev);
 22 
 23     public abstract boolean isScaling();
 24 
 25     public static interface OnGestureListener {
 26         public void onDrag(float dx, float dy);
 27 
 28         public void onFling(float startX, float startY, float velocityX, float velocityY);
 29 
 30         public void onScale(float scaleFactor, float focusX, float focusY);
 31     }
 32 
 33     // <2.0 
 34     private static class CupcakeDetector extends VersionedGestureDetector {
 35 
 36         float mLastTouchX;
 37         float mLastTouchY;
 38         final float mTouchSlop;
 39         final float mMinimumVelocity;
 40 
 41         public CupcakeDetector(Context context) {
 42             final ViewConfiguration configuration = ViewConfiguration.get(context);
 43             mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
 44             mTouchSlop = configuration.getScaledTouchSlop();
 45         }
 46 
 47         private VelocityTracker mVelocityTracker;
 48         private boolean mIsDragging;
 49 
 50         float getActiveX(MotionEvent ev) {
 51             return ev.getX();
 52         }
 53 
 54         float getActiveY(MotionEvent ev) {
 55             return ev.getY();
 56         }
 57 
 58         public boolean isScaling() {
 59             return false;
 60         }
 61 
 62         @Override
 63         public boolean onTouchEvent(MotionEvent ev) {
 64             switch (ev.getAction()) {
 65                 case MotionEvent.ACTION_DOWN: {
 66                     mVelocityTracker = VelocityTracker.obtain();
 67                     mVelocityTracker.addMovement(ev);
 68 
 69                     mLastTouchX = getActiveX(ev);
 70                     mLastTouchY = getActiveY(ev);
 71                     mIsDragging = false;
 72                     break;
 73                 }
 74                 case MotionEvent.ACTION_MOVE: {
 75                     final float x = getActiveX(ev);
 76                     final float y = getActiveY(ev);
 77                     final float dx = x - mLastTouchX, dy = y - mLastTouchY;
 78 
 79                     if (!mIsDragging) {
 80                         // Use Pythagoras to see if drag length is larger than
 81                         // touch slop
 82                         mIsDragging = FloatMath.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;
 83                     }
 84 
 85                     if (mIsDragging) {
 86                         mListener.onDrag(dx, dy);
 87                         mLastTouchX = x;
 88                         mLastTouchY = y;
 89 
 90                         if (null != mVelocityTracker) {
 91                             mVelocityTracker.addMovement(ev);
 92                         }
 93                     }
 94                     break;
 95                 }
 96 
 97                 case MotionEvent.ACTION_CANCEL:
 98                 case MotionEvent.ACTION_UP: {
 99                     if (mIsDragging) {
100                         mIsDragging = false;
101 
102                         if (null != mVelocityTracker) {
103                             mLastTouchX = getActiveX(ev);
104                             mLastTouchY = getActiveY(ev);
105 
106                             // Compute velocity within the last 1000ms
107                             mVelocityTracker.addMovement(ev);
108                             mVelocityTracker.computeCurrentVelocity(1000);
109 
110                             final float vX = mVelocityTracker.getXVelocity(), vY = mVelocityTracker.getYVelocity();
111 
112                             // If the velocity is greater than minVelocity, call
113                             // listener
114                             if (Math.max(Math.abs(vX), Math.abs(vY)) >= mMinimumVelocity) {
115                                 mListener.onFling(mLastTouchX, mLastTouchY, -vX, -vY);
116                             }
117                         }
118                     }
119 
120                     // Recycle Velocity Tracker
121                     if (null != mVelocityTracker) {
122                         mVelocityTracker.recycle();
123                         mVelocityTracker = null;
124                     }
125                     break;
126                 }
127             }
128             return true;
129         }
130     }
131 
132     // =2.0 =2.1
133     private static class EclairDetector extends CupcakeDetector {
134         private static final int INVALID_POINTER_ID = -1;
135         private int mActivePointerId = INVALID_POINTER_ID;
136         private int mActivePointerIndex = 0;
137 
138         public EclairDetector(Context context) {
139             super(context);
140         }
141 
142         @Override
143         float getActiveX(MotionEvent ev) {
144             try {
145                 return ev.getX(mActivePointerIndex);
146             } catch (Exception e) {
147                 return ev.getX();
148             }
149         }
150 
151         @Override
152         float getActiveY(MotionEvent ev) {
153             try {
154                 return ev.getY(mActivePointerIndex);
155             } catch (Exception e) {
156                 return ev.getY();
157             }
158         }
159 
160         @Override
161         public boolean onTouchEvent(MotionEvent ev) {
162             final int action = ev.getAction();
163             switch (action & MotionEvent.ACTION_MASK) {
164                 case MotionEvent.ACTION_DOWN:
165                     mActivePointerId = ev.getPointerId(0);
166                     break;
167                 case MotionEvent.ACTION_CANCEL:
168                 case MotionEvent.ACTION_UP:
169                     mActivePointerId = INVALID_POINTER_ID;
170                     break;
171                 case MotionEvent.ACTION_POINTER_UP:
172                     final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
173                     final int pointerId = ev.getPointerId(pointerIndex);
174                     if (pointerId == mActivePointerId) {
175                         // This was our active pointer going up. Choose a new
176                         // active pointer and adjust accordingly.
177                         final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
178                         mActivePointerId = ev.getPointerId(newPointerIndex);
179                         mLastTouchX = ev.getX(newPointerIndex);
180                         mLastTouchY = ev.getY(newPointerIndex);
181                     }
182                     break;
183             }
184 
185             mActivePointerIndex = ev.findPointerIndex(mActivePointerId != INVALID_POINTER_ID ? mActivePointerId : 0);
186             return super.onTouchEvent(ev);
187         }
188     }
189 
190     // >=2.2 add a ScaleGestureDetector
191     private static class FroyoDetector extends EclairDetector implements ScaleGestureDetector.OnScaleGestureListener {
192         private ScaleGestureDetector mDetector;
193 
194         public FroyoDetector(Context context) {
195             super(context);
196             mDetector = new ScaleGestureDetector(context, this);
197         }
198 
199         @Override
200         public boolean isScaling() {
201             return mDetector.isInProgress();
202         }
203 
204         @Override
205         public boolean onScale(ScaleGestureDetector detector) {
206             mListener.onScale(detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY());
207             return true;
208         }
209 
210         @Override
211         public boolean onTouchEvent(MotionEvent ev) {
212             mDetector.onTouchEvent(ev);
213             return super.onTouchEvent(ev);
214         }
215 
216         @Override
217         public boolean onScaleBegin(ScaleGestureDetector detector) {
218             return true;
219         }
220 
221         @Override
222         public void onScaleEnd(ScaleGestureDetector detector) {
223             // NO-OP
224         }
225     }
226 }
原文地址:https://www.cnblogs.com/phj981805903/p/3283004.html