GestureDetector

An overview of the

This class is mainly used to identify certain gestures, we only need to call the GestureDetector. OnTouchEvent (), and passing the MotionEvent in can. Callbacks for various gestures can be done through the interface OnGestureListener in the GestureDetector.

Just call GestureDetector#onTouchEvent() in View#onTouchEvent().

OnGestureListener

onDown

/**
         * Notified when a tap occurs with the down {@link MotionEvent}
         * that triggered it. This will be triggered immediately for
         * every down event. All other events should be preceded by this.
         *
         * @param e The down motion event.
         */
        boolean onDown(MotionEvent e);Copy the code

In the GestureDetector. OnTouchEvent (), as action_down occurs, this method will be called immediately. The source code for:

Case MotionEvent. ACTION_DOWN:... 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;Copy the code

GestureDetector. OnTouchEvent (), the return value is handled in the last sentence, and in every call this method when handled by initialize false. Therefore, this method will eventually affect the return value of onTouchEvent(). If onDown() returns true, onTouchEvent() must return true; Otherwise, it doesn’t have to return false(because the omitted part has been altered to handle it).

onShowPress 

/** * The user has performed a down {@link MotionEvent} and not performed * a move or up yet. This event is commonly used to provide visual * feedback to the user to let them know that their action has been * recognized i.e. highlight an  element. * * @param e The down motion event */ void onShowPress(MotionEvent e);Copy the code
mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT);Copy the code

OnDown () is executed at action_down event, whether the touch develops into press or scroll. OnShowPress, on the other hand, is executed only if the event is press(held down long enough and not moved widely). It is generally used to tell the user that you have pressed the event, not to click on the event because it might be found as onLongPress.

onLongPress

This is similar to onShowPress() except that onLongPress is executed for a long time and onShowPress() is executed for a short time. As you can see from the source in onDown, onLongPress() is only possible when mIsLongpressEnabled=true.

This value defaults to true when new GestureDetector is used. This can be set with setIsLongpressEnabled().

onSingleTapUp

/**
         * Notified when a tap occurs with the up {@link MotionEvent}
         * that triggered it.
         *
         * @param e The up motion event that completed the first tap
         * @return true if the event is consumed, else false
         */
        boolean onSingleTapUp(MotionEvent e);Copy the code
case MotionEvent.ACTION_UP:
            mStillDown = false;
            MotionEvent currentUpEvent = MotionEvent.obtain(ev);
            if (mIsDoubleTapping) {
                // Finally, give the up event of the double-tap
                handled |= mDoubleTapListener.onDoubleTapEvent(ev);
            } else if (mInLongPress) {
                mHandler.removeMessages(TAP);
                mInLongPress = false;
            } else if (mAlwaysInTapRegion) {
                handled = mListener.onSingleTapUp(ev);Copy the code

As you can see, this is only executed if mIsDoubleTapping=false,mInLongPress=false, and mAlwaysInTapRegion=true.

Viewconfiguration.get (context).getScaledTouchSlop(); viewConfiguration.get (context).getScaledTouchSlop(); MAlwaysInTapRegion = false, mInLongPress = true, mIsDoubleTapping = true for double click events, OnSingleTapUp () is not executed at this point. Therefore, the method is executed when the short click event is lifted, and its MotionEvent has only Action_UP events.

Note: The return value of viewConfiguration.get (context).getScaledTouchSlop() is often used to determine whether to move or click. After the user presses the button, it will shake continuously. During the shaking process, ACTION_MOVE will be triggered continuously. If ev.getx () and ev.gety () are not the same, it is not reasonable. It is reasonable to consider sliding when the distance between ev.getx () and ev.gety () is large enough, and viewConfiguration.get (context).getScaledTouchSlop() is the criterion for judging this distance.

onScroll

/** * Notified when a scroll occurs with the initial on down {@link MotionEvent} and the * current move {@link MotionEvent}. The distance in x and y is also supplied for * convenience. * * @param e1 The first down motion event that  started the scrolling. * @param e2 The move motion event that triggered the current onScroll. * @param distanceX The distance along the X axis that has been scrolled since the last * call to onScroll. This is NOT the distance between {@code e1} * and {@code e2}. * @param distanceY The distance along the Y axis that has been scrolled since the last * call to onScroll. This is NOT the distance between {@code e1} * and {@code e2}. * @return true if the event is consumed,  else false */ boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);Copy the code
else if (mAlwaysInTapRegion) { final int deltaX = (int) (x - mCurrentDownEvent.getX()); final int deltaY = (int) (y - mCurrentDownEvent.getY()); int distance = (deltaX * deltaX) + (deltaY * deltaY); If (distance > mTouchSlopSquare) {distance > mTouchSlopSquare is handled as mlistener. onScroll(mCurrentDownEvent, ev, scrollX, scrollY); mLastMotionX = x; mLastMotionY = y; mAlwaysInTapRegion = false; mHandler.removeMessages(TAP); mHandler.removeMessages(SHOW_PRESS); // Remove the onShowPress callback mhandler. removeMessages(LONG_PRESS); // Remove longpress} if (distance > mBiggerTouchSlopSquare) {mAlwaysInBiggerTapRegion = false; } } else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) { handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY); mLastMotionX = x; mLastMotionY = y; }Copy the code

onFling

This method is called only once when the finger is away from the screen and the swipe speed is fast enough. Note: This method is not called when the screen is scrolling.

final VelocityTracker velocityTracker = mVelocityTracker;
                velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
                final float velocityY = velocityTracker.getYVelocity();
                final float velocityX = velocityTracker.getXVelocity();

                if ((Math.abs(velocityY) > mMinimumFlingVelocity)
                        || (Math.abs(velocityX) > mMinimumFlingVelocity)){
                    handled = mListener.onFling(mCurrentDownEvent, ev, velocityX, velocityY);
                }Copy the code


OnDoubleTapListener

It is another interface in the GestureDetector and is primarily used to handle double click events. This can be set by calling setOnDoubleTapListener() or by passing in SimpleOnGestureListener when new GestureDetector().

onSingleTapConfirmed

/**
         * Notified when a single-tap occurs.
         * <p>
         * Unlike {@link OnGestureListener#onSingleTapUp(MotionEvent)}, this
         * will only be called after the detector is confident that the user's
         * first tap is not followed by a second tap leading to a double-tap
         * gesture.
         *
         * @param e The down motion event of the single-tap.
         * @return true if the event is consumed, else false
         */
        boolean onSingleTapConfirmed(MotionEvent e);Copy the code

Short click event

When we double click, only onSingleTapUp will be executed, not onSingleTapConfirmed; When we click, both are executed.

onDoubleTap

        /**
         * Notified when a double-tap occurs.
         *
         * @param e The down motion event of the first tap of the double-tap.
         * @return true if the event is consumed, else false
         */
        boolean onDoubleTap(MotionEvent e);Copy the code

onDoubleTapEvent   

/** * Notified when an event within a double-tap gesture occurs, including * the down, move, and up events. * * @param e The motion event that occurred during the double-tap gesture. * @return true if the event is  consumed, else false */ boolean onDoubleTapEvent(MotionEvent e);Copy the code

When action_down:

// 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);Copy the code

When action_move:

 if (mIsDoubleTapping) {
                // Give the move events of the double-tap
                handled |= mDoubleTapListener.onDoubleTapEvent(ev);
            } else if (mAlwaysInTapRegion) {Copy the code

The only place where mIsDoubleTapping = true is in the action_down code above. Action_up is similar to action_move.

Therefore, it can be seen that the onDoubleTapEvent is executed after the onDoubleTap, and its MotionEvent down, Move, and Up are all hit second in the double click event.

conclusion

Click: Select onSingleTapUp.

Long press: Select onLongPress.

Show the effect: select onShowPress() – this method has show, which is mainly used to show the effect. The click event cannot be handled in this method because it might develop into LongPress.

Drag: Select onScroll.

Quick Slide: Select onFling.

Double-click: Select onDoubleTap. It’s not a good choice either, but it’s the best of several.

ScaleGestureDetector

An overview of the

The utility class used to handle scaling is used in the same way as the GestureDetector, which associates the corresponding MotionEvent with onTouchEvent(). To use this class, the user passes in a complete continuous motion event (ACTION_DOWN,ACTION_MOVE, and ACTION_UP events).

OnScaleGestureListener

The callback interface in ScaleGestureDetector. There are three main approaches.

onScale

When scaling. The return value represents whether the scaling event has been processed. If it has been processed, the Detector resets the zoom event; If it is not processed, Detector proceeds to compute, modifying the return value of getScaleFactor() until it is processed. Therefore, it is often used to determine that the scaling value only reaches a certain value before scaling. Such as:

public boolean onScale(ScaleGestureDetector detector) {
		System.out.println(detector.getScaleFactor());
		if(detector.getScaleFactor()< 2){
			return false;
		}
		mMatrix.preScale(detector.getScaleFactor(), detector.getScaleFactor());
		setImageMatrix(mMatrix);
		return true;
	}Copy the code



As you can see, the value returned by getScaleFactor() increases from small to greater than 2 and then from 1 again. This is because when the scale factor (return value of getScaleFactor()) is less than 2, onScale() returns false. At this point, the Detector thinks that the scale is not finished yet, so the scale factor calculation again is still based on the end of the previous time, which leads to the scaling parameter getting bigger and bigger when the finger moves out. When the scale reaches 2, the base of the scaling factor will be changed to the position just ended when the scaling factor is obtained again. Therefore, the obtained scaling factor will suddenly become smaller (because the finger moves out to perform the zoom operation, so the scaling factor will be greater than 1).

onScaleBegin

Zoom starts. Whether the detector handles subsequent scaling events. OnScale () is not executed when false is returned.

onScaleEnd

At the end of the zoom.

Commonly used method

www.haodaima.net/art/1742556

OnTouchEvent () : Associated with MotionEvent. Returning true indicates that the Detector wants to continue receiving subsequent Motion events; Otherwise, vice versa. This method returns true by default.

GetScaleFactor () : Gets the scaling factor of this scaling event (the scaling event is based on the value returned by onScale(). Once this method returns true, this event is over and the next event should be started). Its return value refers to the scale value in this event, not relative to the original value. For example, a picture was enlarged by 2 times, and then by 1.1 times. On the second magnification, the method returns 1.1 instead of the total magnification: 2*1.1.

GetCurrentSpan () : Returns the current distance between the two contacts that make up the gesture during the gesture. Returns the contact distance in pixels.

GetCurrentSpanX (),getCurrentSpanY() : Similar to getCurrentSpan(), except that one returns the distance on the x axis and the other returns the distance on the y axis. Note: The return value may be negative. The return value of these two methods and the return value of getCurrentSpan() satisfy the Pythagorean theorem.

GetFocusY (),getFocusX() : Returns the y and x coordinates on the component, in pixels, of the midpoints of the two contacts that make up the gesture.

GetPreviousSpan () : Returns the previous distance between the two contacts that make up the current zoom gesture during the zoom process. Suppose you have three fingers a, B and C, and a pinch gesture is formed by A and B at a distance of 300; Then b and C form the zoom gesture, and when C is lifted, B and C are 100 away. In this case, ab will form the zoom gesture and return 300 instead of 100 for b and C.

GetPreviousSpanX (),getPreviousSpanY() : similar to getPreviousSpan().

GetEventTime () : gets the time of the current motion event. The source code is as follows:

public boolean onTouchEvent(MotionEvent event) { if (mInputEventConsistencyVerifier ! = null) { mInputEventConsistencyVerifier.onTouchEvent(event, 0); } mCurrTime = event.getEventTime(); // This method returns the value of mCurrTimeCopy the code



It started at 1586, and the next time it immediately became 10. This is because at 1586, onScale returned true, the Detector thought that the scaling event had ended, and the calculation would start again when deltatime was acquired, so the value suddenly decreased to 10.

IsInProgress () : returns true if the pinch gesture isInProgress; Otherwise return false.