API google provided, there is a class, we are familiar with, GestureDetector. Use it, we can identify the user usually use gestures. However, this class does not support multi-touch (do not think anyone could google in a few fingers on the screen, use gestures it ~), however, and my friends do together recent App, indeed used a multi-point gestures (mainly onScroll and onFling two gestures), so I took this class to expand a bit, to achieve so that each followed by a number of controls to achieve the effect of dragging with your finger and sliding.
By the way, we should all know, Android3.0 after allocation mechanisms Android touch events and previous versions are different. Starting with 3.0, touch Messaging users on different operating controls do not interfere with each other to produce, touch the message will be assigned to a different control on touchListener processing. The
In previous versions, all touch messages will be routed to the first encounter of the screen controls the operation of the fingers of touchListener processing, that is, is there such a contradictory phenomenon:
On the interface has A, B, C three controls, and then, when you first use the index finger and hold the A, and then again with the middle finger and ring finger (Well, other fingers also, do not care about the middle finger or ring finger) and hold the B, C . And moving means which, when the ring finger, B and C can not receive the ACTION_MOVE message and the received message is A. In version 3.0 and above, this problem does not exist.
Use the following class, can be achieved from the 2.2 to 3.2 gesture recognition platform compatible.
Started paste code:
package com.finger.utils;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
public class MultiTouchGestureDetector {
@ SuppressWarnings ("unused")
private static final String MYTAG = "Ray";
public static final String CLASS_NAME = "MultiTouchGestureDetector";
/ **
* Event Info
* Is used to record a gesture
* /
private class EventInfo {
private MultiMotionEvent mCurrentDownEvent; / / current events
downprivate MultiMotionEvent mPreviousUpEvent; / / The last time up event
whether the finger is still on the screen / / current; private boolean mStillDownprivate boolean mInLongPress; / / current event is long press gesture
private boolean mAlwaysInTapRegion; / / if the current finger to move only in a small area, when the finger moves only in a small area, deemed never moved a finger, gesture
not trigger onScrollprivate boolean mAlwaysInBiggerTapRegion; / / if the current finger in a wide range of mobile, only when this is true, double-click gesture can be established
private boolean mIsDoubleTapping; / / this gesture, whether as a double-click gesture
private float mLastMotionY; / / X coordinate
last eventprivate float mLastMotionX; / / Y coordinate
last event
private EventInfo (MotionEvent e) {
this (new MultiMotionEvent (e));
}
private EventInfo (MultiMotionEvent me) {
mCurrentDownEvent = me;
mStillDown = true;
mInLongPress = false;
mAlwaysInTapRegion = true;
mAlwaysInBiggerTapRegion = true;
mIsDoubleTapping = false;
}
/ / Release MotionEven object, enabling the system to continue to use them
public void recycle () {
if (mCurrentDownEvent! = null) {
mCurrentDownEvent.recycle ();
mCurrentDownEvent = null;
}
if (mPreviousUpEvent! = null) {
mPreviousUpEvent.recycle ();
mPreviousUpEvent = null;
}
}
@ Override
public void finalize () {
this.recycle ();
}
}
/ **
* Multi-point event class
* A multi-point event will be split into multiple single-point event, and convenient access to the absolute coordinate
event*
Absolute coordinates of where to find contacts in the interface controls
* @ Author ray-ni
* /
public class MultiMotionEvent {
private MotionEvent mEvent;
private int mIndex;
private MultiMotionEvent (MotionEvent e) {
mEvent = e;
mIndex = (e.getAction () & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT; / / equivalent to mEvent.getActionIndex ();
}
private MultiMotionEvent (MotionEvent e, int idx) {
mEvent = e;
mIndex = idx;
}
/ / Behavior
public int getAction () {
int action = mEvent.getAction () & MotionEvent.ACTION_MASK; / / equivalent to mEvent.getActionMasked ();
switch (action) {
case MotionEvent.ACTION_POINTER_DOWN:
action = MotionEvent.ACTION_DOWN;
break;
case MotionEvent.ACTION_POINTER_UP:
action = MotionEvent.ACTION_UP;
break;
}
return action;
}
/ / Returns the absolute coordinates X
public float getX () {
return mEvent.getX (mIndex) + mEvent.getRawX () - mEvent.getX ();
}
/ / Returns the absolute Y coordinate
public float getY () {
return mEvent.getY (mIndex) + mEvent.getRawY () - mEvent.getY ();
}
/ / Time the event occurred
public long getEventTime () {
return mEvent.getEventTime ();
}
/ / Event number
public int getIndex () {
return mIndex;
}
/ / Event ID
public int getId () {
return mEvent.getPointerId (mIndex);
}
/ / Release event object, enabling the system to continue to use
public void recycle () {
if (mEvent! = null) {
mEvent.recycle ();
mEvent = null;
}
}
}
/ / Multi-point gesture listener
public interface MultiTouchGestureListener {
/ / Finger touches the screen, triggered by an ACTION_DOWN
boolean onDown (MultiMotionEvent e);
/ / Define a press event, the emphasis in the finger pressing period (TAP_TIMEOUT), never move or lift the finger
void onShowPress (MultiMotionEvent e);
/ / Finger tap the screen after leaving from ACTION_UP triggered, can simply be understood as the click event, that time is not long finger tap (not constitute a long press event), nor had moved
boolean onSingleTapUp (MultiMotionEvent e);
/ / Long press, over a period of time under the finger points (DOUBLE_TAP_TIMEOUT), did not lift or move
void onLongPress (MultiMotionEvent e);
/ / Drag, triggered by ACTION_MOVE, after pressing a finger to move the screen
boolean onScroll (MultiMotionEvent e1, MultiMotionEvent e2, float distanceX, float distanceY);
/ / Slide, triggered by ACTION_UP, finger pressing and moving some distance, lift the trigger
boolean onFling (MultiMotionEvent e1, MultiMotionEvent e2, float velocityX, float velocityY);
}
/ / Multi-point double-click the listener
public interface MultiTouchDoubleTapListener {
/ / Click event recognition, stressed after a click event occurs over a period of time, the second click event does not occur, that certainly will not trigger double-click event
boolean onSingleTapConfirmed (MultiMotionEvent e);
/ / Double-click events, triggered by ACTION_DOWN, the end of the event from the first click DOWN event started some time (DOUBLE_TAP_TIMEOUT) (ie finger),
/ / And for some time after the first time in UP click event begins (DOUBLE_TAP_TIMEOUT) second click event occurs,
When / / In addition to the two coordinate spacing is less than a given value (DOUBLE_TAP_SLAP), then double-click the event triggering
boolean onDoubleTap (MultiMotionEvent e);
/ / Double-click events, and onDoubleTap event except that constitutes the second click of a double-click ACTION_DOWN, ACTION_MOVE and ACTION_UP will trigger the event
boolean onDoubleTapEvent (MultiMotionEvent e);
}
/ / Event message queue, the queue subscript and MotionEvent of pointId corresponding
private static ListsEventInfos = new ArrayList (10);
/ / Double-judgment queue elements in the queue waiting for a timeout determination result
Double-private static ListsEventForDoubleTap = new ArrayList (5);
/ / Specify the size (this mouthful) big hit region, this value is mainly used to help determine whether to establish
double-clickprivate int mBiggerTouchSlopSquare = 20 * 20;
/ / Determine whether the constitution onScroll gestures, when a finger moves within this range, do not trigger onScroll gesture
private int mTouchSlopSquare;
/ / Determine whether constitute double click, only two clicks of the distance is less than this value, in order to constitute a double-click gesture
private int mDoubleTapSlopSquare;
/ / Minimum sliding velocity
private int mMinimumFlingVelocity;
/ / Maximum sliding speed
private int mMaximumFlingVelocity;
/ / Long press threshold, when the finger is pressed within the threshold time, distance does not move more than mTouchSlopSquare not raised, then long press gesture triggers
private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout ();
/ / ShowPress gesture trigger threshold, when the finger is pressed within the threshold time has not moved a distance of not more than mTouchSlopSquare lift the showPress gesture triggers
private static final int TAP_TIMEOUT = ViewConfiguration.getTapTimeout ();
/ / Double-click timeout threshold, only two double-click the event in the interval (the first event and clicked UP DOWN second click of the event) is less than this threshold, double-click the event can be established
private static final int DOUBLE_TAP_TIMEOUT = ViewConfiguration.getDoubleTapTimeout ();
/ / Double-click Regional threshold, at a distance of only two double-click the event is less than this threshold, double-click the event can be established
private static final int DOUBLE_TAP_SLAP = 64;
Message of what attributes / / GestureHandler may be handled by the following constants:
/ / ShowPress gesture
private static final int SHOW_PRESS = 1;
/ / Long press gesture
private static final int LONG_PRESS = 2;
/ / SingleTapConfirmed gesture
private static final int TAP_SINGLE = 3;
/ / Double-click gesture
private static final int TAP_DOUBLE = 4;
/ / Gesture processor
private final GestureHandler mHandler;
/ / Gesture listener
private final MultiTouchGestureListener mListener;
/ / Double-click the listener
private MultiTouchDoubleTapListener mDoubleTapListener;
/ / Long press allows the threshold
private boolean mIsLongpressEnabled;
/ / Speed Tracker
private VelocityTracker mVelocityTracker;
private class GestureHandler extends Handler {
GestureHandler () {
super ();
}
GestureHandler (Handler handler) {
super (handler.getLooper ());
}
@ Override
public void handleMessage (Message msg) {
int idx = (Integer) msg.obj;
switch (msg.what) {
case SHOW_PRESS: {
if (idx> = sEventInfos.size ()) {
/ / Log.w (MYTAG, CLASS_NAME + ": handleMessage, msg.what = SHOW_PRESS, idx =" + idx + ", while sEventInfos.size () ="
/ / + SEventInfos.size ());
break;
}
EventInfo info = sEventInfos.get (idx);
if (info == null) {
/ / Log.e (MYTAG, CLASS_NAME + ": handleMessage, msg.what = SHOW_PRESS, idx =" + idx + ", Info = null");
break;
}
/ / Trigger gesture listener onShowPress event
mListener.onShowPress (info.mCurrentDownEvent);
break;
}
case LONG_PRESS: {
/ / Log.d (MYTAG, CLASS_NAME + ": trigger LONG_PRESS");
if (idx> = sEventInfos.size ()) {
/ / Log.w (MYTAG, CLASS_NAME + ": handleMessage, msg.what = LONG_PRESS, idx =" + idx + ", while sEventInfos.size () ="
/ / + SEventInfos.size ());
break;
}
EventInfo info = 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;
}
case TAP_SINGLE: {
/ / Log.d (MYTAG, CLASS_NAME + ": trriger TAP_SINGLE");
/ / If the user's finger is still down, do not count it as a tap
if (idx> = sEventInfos.size ()) {
/ / Log.e (MYTAG, CLASS_NAME + ": handleMessage, msg.what = TAP_SINGLE, idx =" + idx + ", while sEventInfos.size () ="
/ / + SEventInfos.size ());
break;
}
EventInfo info = 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) {/ / finger in the double-click timeout threshold does not leave the screen for a second click event, click the event to determine the establishment (not trigger double-click event)
mDoubleTapListener.onSingleTapConfirmed (info.mCurrentDownEvent);
}
break;
}
case TAP_DOUBLE: {
if (idx> = sEventForDoubleTap.size ()) {
/ / Log.w (MYTAG, CLASS_NAME + ": handleMessage, msg.what = TAP_DOUBLE, idx =" + idx + ", while sEventForDoubleTap.size () ="
/ / + SEventForDoubleTap.size ());
break;
}
EventInfo info = 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) ;/ / this is nothing to do, is to remove the corresponding element in the queue just
break;
}
default:
throw new RuntimeException ("Unknown message" + msg); / / never
}
}
}
/ **
* Long press the trigger event
* @ Param info
* @ Param idx
* /
private void dispatchLongPress (EventInfo info, int idx) {
mHandler.removeMessages (TAP_SINGLE, idx) ;/ / remove the click event confirmed
info.mInLongPress = true;
mListener.onLongPress (info.mCurrentDownEvent);
}
Reply:
/ **
* Constructor 1
* @ Param context
* @ Param listener
* /
public MultiTouchGestureDetector (Context context, MultiTouchGestureListener listener) {
this (context, listener, null);
}
/ **
* Constructor 2
* @ Param context
* @ Param listener
* @ Param handler
* /
public MultiTouchGestureDetector (Context context, MultiTouchGestureListener listener, Handler handler) {
if (handler! = null) {
mHandler = new GestureHandler (handler);
} Else {
mHandler = new GestureHandler ();
}
mListener = listener;
if (listener instanceof MultiTouchDoubleTapListener) {
setOnDoubleTapListener ((MultiTouchDoubleTapListener) listener);
}
init (context);
}
/ **
* Initialize the recognizer
* @ Param context
* /
private void init (Context context) {
if (mListener == null) {
throw new NullPointerException ("OnGestureListener must not be null");
}
mIsLongpressEnabled = true;
int touchSlop, doubleTapSlop;
if (context == null) {
touchSlop = ViewConfiguration.getTouchSlop ();
doubleTapSlop = DOUBLE_TAP_SLAP;
mMinimumFlingVelocity = ViewConfiguration.getMinimumFlingVelocity ();
mMaximumFlingVelocity = ViewConfiguration.getMaximumFlingVelocity ();
} Else {/ / allow the recognizer in the App, the settings
preferencesfinal ViewConfiguration configuration = ViewConfiguration.get (context);
touchSlop = configuration.getScaledTouchSlop ();
doubleTapSlop = configuration.getScaledDoubleTapSlop ();
mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity ();
mMaximumFlingVelocity = configuration.getScaledMaximumFlingVelocity ();
}
mTouchSlopSquare = touchSlop * touchSlop / 16;
mDoubleTapSlopSquare = doubleTapSlop * doubleTapSlop;
}
/ **
* Set the double-click listener
* @ Param onDoubleTapListener
* /
public void setOnDoubleTapListener (MultiTouchDoubleTapListener onDoubleTapListener) {
mDoubleTapListener = onDoubleTapListener;
}
/ **
* Set whether to allow long press
* @ Param isLongpressEnabled
* /
public void setIsLongpressEnabled (boolean isLongpressEnabled) {
mIsLongpressEnabled = isLongpressEnabled;
}
/ **
* Determine whether to allow long press
* @ Return
* /
public boolean isLongpressEnabled () {
return mIsLongpressEnabled;
}
/ **
* Determine whether the current event as a double-click event
*
By traversing sEventForDoubleTap whether there can be constructed to match the double-click event click event
* @ Param e
* @ Return
* /
private EventInfo checkForDoubleTap (MultiMotionEvent e) {
if (sEventForDoubleTap.isEmpty ()) {
/ / Log.e (MYTAG, CLASS_NAME + ":! CheckForDoubleTap (), sEventForDoubleTap is empty");
return null;
}
for (int i = 0; iEventInfo info = sEventForDoubleTap.get (i);
if (info! = null && isConsideredDoubleTap (info, e)) {
sEventForDoubleTap.set (i, null) ;/ / this click event has been consumed, so set to null
mHandler.removeMessages (TAP_DOUBLE, i) ;/ / remove
Handler to process messages withinreturn info;
}
}
return null;
}
/ **
* Determine whether the current press event and specify the click event constitute double click event
*
* @ Param info
* @ Param secondDown
* @ Return
* /
private boolean isConsideredDoubleTap (EventInfo info, MultiMotionEvent secondDown) {
move if (! info.mAlwaysInBiggerTapRegion) {/ / If there is more than a click event for the first time over a greater distance, you can not double-click events constitute
return false;
}
if (secondDown.getEventTime () - info.mPreviousUpEvent.getEventTime ()> DOUBLE_TAP_TIMEOUT) {
/ / If the first time you click the UP time and the second click of down time interval is greater than DOUBLE_TAP_TIMEOUT, can not constitute a double-click event
return false;
}
int deltaX = (int) info.mCurrentDownEvent.getX () - (int) secondDown.getX ();
int deltaY = (int) info.mCurrentDownEvent.getY () - (int) secondDown.getY ();
return (deltaX * deltaX + deltaY * deltaY}
/ **
* Double-click on the event information into judgment queue and returns the serial number
*
* @ Param info
* @ Return
* /
private int addIntoTheMinIndex (EventInfo info) {
for (int i = 0; iif (sEventForDoubleTap.get (i) == null) {
sEventForDoubleTap.set (i, info);
return i;
}
}
sEventForDoubleTap.add (info);
return sEventForDoubleTap.size () - 1;
}
/ **
* Removes the specified number of events from the event message queue
*
* @ Param idx
* /
private void removeEventFromList (int id) {
if (id> sEventInfos.size () | | id <0) {
/ / Log.e (MYTAG, CLASS_NAME + + id + ", while sEventInfos.size () =" + sEventInfos.size () "removeEventFromList (), id =.");
return;
}
sEventInfos.set (id, null);
}
/ **
* Add new information to the event queue
*
* @ Param e
* /
private void addEventIntoList (EventInfo info) {
int id = info.mCurrentDownEvent.getId ();
if (id/ / If (sEventInfos.get (id)! = Null)
/ / Log.e (MYTAG, CLASS_NAME + + id + ") has not set to null!" "AddEventIntoList, info (.");
sEventInfos.set (info.mCurrentDownEvent.getId (), info);
} Else if (id == sEventInfos.size ()) {
sEventInfos.add (info);
} Else {
/ / Log.e (MYTAG, CLASS_NAME + "addEventIntoList, invalidata id.!");
}
}
Reply:
public boolean onTouchEvent (MotionEvent ev) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain ();
}
mVelocityTracker.addMovement (ev) ;/ / put all events are added to the speed tracker, to prepare for the calculation speed
boolean handled = false;
final int action = ev.getAction (); / / Get Action
/ / Int idx = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT ;/ / Get number
touch eventsint idx = ev.getPointerId (ev.getActionIndex ()) ;/ / get id
touch events
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN: {
EventInfo info = new EventInfo (MotionEvent.obtain (ev));
this.addEventIntoList (info) ;/ / Save the gesture information to the queue
if (mDoubleTapListener! = null) {/ / If you double-click the listener is not null
if (mHandler.hasMessages (TAP_DOUBLE)) {
MultiMotionEvent e = new MultiMotionEvent (ev);
EventInfo origInfo = checkForDoubleTap (e) ;/ / checks would constitute double click event
if (origInfo! = null) {
info.mIsDoubleTapping = true;
handled | = mDoubleTapListener.onDoubleTap (origInfo.mCurrentDownEvent);
handled | = mDoubleTapListener.onDoubleTapEvent (e);
}
}
if (! info.mIsDoubleTapping) {/ / this event does not constitute a double-click event, then send the message to determine onSingleTapConfirmed delayed event
mHandler.sendMessageDelayed (mHandler.obtainMessage (TAP_SINGLE, idx), DOUBLE_TAP_TIMEOUT);
/ / Log.d (MYTAG, CLASS_NAME + ": add TAP_SINGLE");
}
}
/ / Record X and Y coordinates
info.mLastMotionX = info.mCurrentDownEvent.getX ();
info.mLastMotionY = info.mCurrentDownEvent.getY ();
if (mIsLongpressEnabled) {/ / allow long press
mHandler.removeMessages (LONG_PRESS, idx);
mHandler.sendMessageAtTime (mHandler.obtainMessage (LONG_PRESS, idx), info.mCurrentDownEvent.getEventTime () + TAP_TIMEOUT
+ LONGPRESS_TIMEOUT) ;/ / delay messages to trigger long press gesture
/ / Log.d (MYTAG, CLASS_NAME +
/ / ": Add LONG_PRESS to handler for idx" + idx);
}
mHandler.sendMessageAtTime (mHandler.obtainMessage (SHOW_PRESS, idx), info.mCurrentDownEvent.getEventTime () + TAP_TIMEOUT) ;/ / delay messages, triggering showPress gesture
handled | = mListener.onDown (info.mCurrentDownEvent) ;/ / trigger onDown ()
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP: {
MultiMotionEvent currentUpEvent = new MultiMotionEvent (ev);
if (idx> = sEventInfos.size ()) {
/ / Log.e (MYTAG, CLASS_NAME + ": ACTION_POINTER_UP, idx =" + idx + ", while sEventInfos.size () =" + sEventInfos.size ());
break;
}
EventInfo info = 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) {/ / double-click in the state, the trigger event
onDoubleTapEventhandled | = mDoubleTapListener.onDoubleTapEvent (currentUpEvent);
} Else if (info.mInLongPress) {/ / in long press state
mHandler.removeMessages (TAP_SINGLE, idx) ;/ / can ignore this line of code
info.mInLongPress = false;
} Else if (info.mAlwaysInTapRegion) {/ / not yet moved
if (mHandler.hasMessages (TAP_SINGLE, idx)) within {/ / also double-click on the time threshold, so to do additional processing
double-click to determinemHandler.removeMessages (TAP_SINGLE, idx);
info.mPreviousUpEvent = new MultiMotionEvent (MotionEvent.obtain (ev));
int index = this.addIntoTheMinIndex (info) ;/ / put current events into the queue, waiting for the judgment
double-clickmHandler.sendMessageAtTime (mHandler.obtainMessage (TAP_DOUBLE, index), info.mCurrentDownEvent.getEventTime ()
+ DOUBLE_TAP_TIMEOUT); / / Add the double-click timeout judgment to Handler
/ / Log.d (MYTAG, CLASS_NAME + ": add TAP_DOUBLE");
}
handled = mListener.onSingleTapUp (currentUpEvent) ;/ / trigger event
onSingleTapUp} Else {
/ / A fling must travel the minimum tap distance
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity (1000, mMaximumFlingVelocity) ;/ / calculate the sliding speed within a second
/ / Get the X and Y direction speed
final float velocityX = velocityTracker.getXVelocity (idx);
final float velocityY = velocityTracker.getYVelocity (idx);
/ / Log.i (MYTAG, CLASS_NAME + ": ACTION_POINTER_UP, idx =" + idx +
/ / ", Vx =" + velocityX + ", vy =" + velocityY);
/ / Trigger event
slideif ((Math.abs (velocityY)> mMinimumFlingVelocity) | | (Math.abs (velocityX)> mMinimumFlingVelocity)) {
handled = mListener.onFling (info.mCurrentDownEvent, currentUpEvent, velocityX, velocityY);
}
}
/ / Hold the event we obtained above - listeners may have changed the
/ / Original.
if (action == MotionEvent.ACTION_UP) {/ / release rate tracker
mVelocityTracker.recycle ();
mVelocityTracker = null;
/ / Log.w (MYTAG, CLASS_NAME +
/ / ": ACTION_POINTER_UP, mVelocityTracker.recycle ()");
}
info.mIsDoubleTapping = false;
/ / Log.d (MYTAG, CLASS_NAME + "remove LONG_PRESS");
/ / Remove showPress and long press the message
mHandler.removeMessages (SHOW_PRESS, idx);
mHandler.removeMessages (LONG_PRESS, idx);
removeEventFromList (currentUpEvent.getId ()) ;/ / fingers away from the queue to delete gesture information
break;
}
case MotionEvent.ACTION_MOVE:
for (int rIdx = 0; rIdx MultiMotionEvent e = new MultiMotionEvent (ev, rIdx);
if (e.getId ()> = sEventInfos.size ()) {
/ / Log.e (MYTAG, CLASS_NAME + ": ACTION_MOVE, idx =" + rIdx + ", while sEventInfos.size () =" + sEventInfos.size ());
break;
}
EventInfo info = sEventInfos.get (e.getId ());
if (info == null) {
/ / Log.e (MYTAG, CLASS_NAME + ": ACTION_MOVE, idx =" + rIdx + ", Info = null");
break;
}
if (info.mInLongPress) {/ / long press, move event is not processed
break;
}
/ / Current coordinates
float x = e.getX ();
float y = e.getY ();
/ / Move the event from the last position
final float scrollX = x - info.mLastMotionX;
final float scrollY = y - info.mLastMotionY;
if (info.mIsDoubleTapping) {/ / double-click events
handled | = mDoubleTapListener.onDoubleTapEvent (e);
} Else if (info.mAlwaysInTapRegion) {/ / This gesture has not moved (the distance traveled is less than mTouchSlopSquare, deemed not to have been moved)
/ / Calculate from falling to the current event, the distance traveled
final int deltaX = (int) (x - info.mCurrentDownEvent.getX ());
final int deltaY = (int) (y - info.mCurrentDownEvent.getY ());
/ / Log.d (MYTAG, CLASS_NAME + "deltaX =" + deltaX + "; deltaY =" +
/ / DeltaX + "mTouchSlopSquare =" + mTouchSlopSquare);
int distance = (deltaX * deltaX) + (deltaY * deltaY);
if (distance> mTouchSlopSquare) {/ / move the distance of more than mTouchSlopSquare
handled = mListener.onScroll (info.mCurrentDownEvent, e, scrollX, scrollY);
info.mLastMotionX = e.getX ();
info.mLastMotionY = e.getY ();
info.mAlwaysInTapRegion = false;
/ / Log.d (MYTAG, CLASS_NAME +
/ / ": Remove LONG_PRESS for idx" + rIdx +
/ / ", MTouchSlopSquare (" + mTouchSlopSquare + "), distance (" + distance + ")");
/ / Clear onSingleTapConform, showPress, longPress three message
int id = e.getId ();
mHandler.removeMessages (TAP_SINGLE, id);
mHandler.removeMessages (SHOW_PRESS, id);
mHandler.removeMessages (LONG_PRESS, id);
}
if (distance> mBiggerTouchSlopSquare) {/ / move the distance is greater than mBiggerTouchSlopSquare, can not constitute a double-click event
info.mAlwaysInBiggerTapRegion = false;
}
} Else if ((Math.abs (scrollX)> = 1) | | (Math.abs (scrollY)> = 1)) {/ / has been moved before the
handled = mListener.onScroll (info.mCurrentDownEvent, e, scrollX, scrollY);
info.mLastMotionX = x;
info.mLastMotionY = y;
}
}
break;
case MotionEvent.ACTION_CANCEL:
cancel () ;/ / cleanup
}
return handled;
}
/ / Clean up any queue
private void cancel () {
mHandler.removeMessages (SHOW_PRESS);
mHandler.removeMessages (LONG_PRESS);
mHandler.removeMessages (TAP_SINGLE);
mVelocityTracker.recycle ();
mVelocityTracker = null;
sEventInfos.clear ();
sEventForDoubleTap.clear ();
}
} Finally, hang a tiny ad here:
I have friends who write App and here, I hope to give a support:
electronics market link address
Youtube demo video 1 (see over the wall)
Youtube demo video 2 (see over the wall)
Reply:
Support that is not easy to write code, thanks for sharing
Reply:
Oh, thank you
Reply:

Reply:
Learn about the support ~
Reply:
123456789dfghfgjgjk
Reply:
Reply:
Support it, and also learn about
Reply:
Reply:
Reply:
Reply:
mark, thanks for sharing, like this one
Reply:
Thank you for sharing, collection, learn!
Reply:
Reply:

Reply:
Reply:
Reply:
Reply:
Reply:
Up early is recommended, for the first time is recommended, very happy ~
Thank you for your support! ~
Reply:
Reply:
Reply:

Reply:
Up early is recommended, for the first time is recommended, very happy ~
Thank you for your support! ~
Reply:
Or use the engine to write faster and more convenient
Reply:
Multi-gesture recognition ...... wood have more equipment ah ......
Reply:
Reply:
Never tried the engine, the low-end. . .
Reply:
Reply:
Why use Unity3D landlord under development for Android convenient cross-platform rapid generation does not attempt APK without any interface
Powerful UI plug-perfect compression of course also includes software signature
Reply:
Reply:
Good NB said. . . Landlord practitioners have for many years it ==!
Reply:
Good eh ~
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
. .
. .
Reply:
. .
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
~
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
~
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
~
Reply:
~
......
Reply:
~
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
* /
}
}
}
Reply:
* /
. .
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
Reply:
. .
Reply:
No comments:
Post a Comment