/******************************************************************************* * Copyright 2011, 2012 Chris Banes. * <p/> * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ package me.xiaopan.sketch.feature.zoom.gestures; import android.content.Context; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.ViewConfiguration; import me.xiaopan.sketch.SLogType; import me.xiaopan.sketch.SLog; public class CupcakeScaleDragGestureDetector implements ScaleDragGestureDetector { private static final String NAME = "CupcakeGestureDetector"; protected final float mTouchSlop; protected final float mMinimumVelocity; protected OnScaleDragGestureListener mListener; protected ActionListener actionListener; protected float mLastTouchX; protected float mLastTouchY; private VelocityTracker mVelocityTracker; private boolean mIsDragging; public CupcakeScaleDragGestureDetector(Context context) { final ViewConfiguration configuration = ViewConfiguration.get(context); mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); mTouchSlop = configuration.getScaledTouchSlop(); } @Override public void setOnGestureListener(OnScaleDragGestureListener listener) { this.mListener = listener; } @Override public void setActionListener(ActionListener actionListener) { this.actionListener = actionListener; } protected float getActiveX(MotionEvent ev) { return ev.getX(); } protected float getActiveY(MotionEvent ev) { return ev.getY(); } @Override public boolean isScaling() { return false; } @Override public boolean isDragging() { return mIsDragging; } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: { mVelocityTracker = VelocityTracker.obtain(); if (null != mVelocityTracker) { mVelocityTracker.addMovement(ev); } else { SLog.w(SLogType.ZOOM, NAME, "Velocity tracker is null"); } mLastTouchX = getActiveX(ev); mLastTouchY = getActiveY(ev); mIsDragging = false; if (actionListener != null) { actionListener.onActionDown(ev); } break; } case MotionEvent.ACTION_MOVE: { final float x = getActiveX(ev); final float y = getActiveY(ev); final float dx = x - mLastTouchX, dy = y - mLastTouchY; if (!mIsDragging) { // Use Pythagoras to see if drag length is larger than // touch slop mIsDragging = Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop; } if (mIsDragging) { mListener.onDrag(dx, dy); mLastTouchX = x; mLastTouchY = y; if (null != mVelocityTracker) { mVelocityTracker.addMovement(ev); } } break; } case MotionEvent.ACTION_CANCEL: { // Recycle Velocity Tracker if (null != mVelocityTracker) { mVelocityTracker.recycle(); mVelocityTracker = null; } if (actionListener != null) { actionListener.onActionCancel(ev); } break; } case MotionEvent.ACTION_UP: { if (mIsDragging) { if (null != mVelocityTracker) { mLastTouchX = getActiveX(ev); mLastTouchY = getActiveY(ev); // Compute velocity within the last 1000ms mVelocityTracker.addMovement(ev); mVelocityTracker.computeCurrentVelocity(1000); final float vX = mVelocityTracker.getXVelocity(), vY = mVelocityTracker .getYVelocity(); // If the velocity is greater than minVelocity, call // listener if (Math.max(Math.abs(vX), Math.abs(vY)) >= mMinimumVelocity) { mListener.onFling(mLastTouchX, mLastTouchY, -vX, -vY); } } } // Recycle Velocity Tracker if (null != mVelocityTracker) { mVelocityTracker.recycle(); mVelocityTracker = null; } if (actionListener != null) { actionListener.onActionUp(ev); } break; } } return true; } }