Demand background

Slide to zoom in and out:
  1. Slide to Enlarge: Hold down the shooting mode and slide your finger upward to enlarge the lens. Slide your finger in any direction to enlarge the area.
  2. Double finger twisting gesture magnification
  3. Timing of sliding and enlarging prompt: long press to shoot for 2 seconds and the prompt will appear and disappear after 2 seconds;
  4. Sliding and enlarging prompt: for the version after the function goes online, the prompt will be given when the first three long presses are taken;

Implementation scheme

Gesture listener

GestureDetector


GestureDetector.OnGestureListener{  
  
        // The user taps the touch screen, triggered by a MotionEvent ACTION_DOWN
        public boolean onDown(MotionEvent e) {  
            Log.i("MyGesture"."onDown");      
            return false;  
        }  
  
        /* * The user touches the touch screen without releasing or dragging it, triggering a 1 MotionEvent ACTION_DOWN The onDown is also triggered by a MotionEventACTION_DOWN, but it has no restrictions. * That is, when the user clicks, first MotionEventACTION_DOWN, the onDown is executed. * onShowPress will be executed if it is not released or dragged at the moment of pressing. If it is held for longer than the moment of pressing *, onShowPress will not be executed if it is dragged. * /  
        public void onShowPress(MotionEvent e) {  
            Log.i("MyGesture"."onShowPress");     
        }  
  
        // The user releases (after tapping the touch screen), triggered by a 1 MotionEvent ACTION_UP
        /// Tap the screen and lift it immediately to trigger it
        As the name implies, a Single tap lift operation is no longer a Single operation if there are operations other than Down, so the event will not respond
        public boolean onSingleTapUp(MotionEvent e) {  
            Log.i("MyGesture"."onSingleTapUp");         
            return true;     
        }  
  
        // The user presses down on the touch screen and drags, which is triggered by 1 MotionEvent ACTION_DOWN and multiple action_moves
        public boolean onScroll(MotionEvent e1, MotionEvent e2,  
                float distanceX, float distanceY) {  
            Log.i("MyGesture22"."onScroll:"+(e2.getX()-e1.getX()) +""+distanceX);     
            return true;     
        }  
  
        // The user presses the touch screen long enough to trigger multiple motionEvents ACTION_DOWN
        public void onLongPress(MotionEvent e) {  
             Log.i("MyGesture"."onLongPress");         
        }  
  
        // The user presses down the touch screen, moves quickly and releases it, which is triggered by 1 MotionEvent ACTION_DOWN, multiple action_Moves and 1 ACTION_UP
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,  float velocityY) { 
            Log.i("MyGesture"."onFling"); 
            return true; }};Copy the code
When do these functions fire?
  • OnDown(MotionEvent E) : Triggered when the user presses the screen;

  • OnShowPress (MotionEvent E) : If it is pressed for more than a moment and it is not released or dragged, then onShowPress will execute.

  • OnLongPress (MotionEvent E) : Long press the touch screen for more than a certain time, it will trigger the event trigger sequence: onDown->onShowPress->onLongPresson

  • SingleTapUp (MotionEvent e) : As you can see from the name, it takes a single tap to lift, a tap to lift the screen immediately, to trigger this, Of course, if there is anything other than Down, it is no longer a Single operation, so it will not trigger the event and trigger the sequence very fast (without sliding) Touchup: OnDown ->onSingleTapUp->onSingleTapConfirmed Click on a slightly slower Touchup: onDown->onShowPress->onSingleTapUp->onSingleTapConfirmed

  • OnFling (MotionEvent E1, MotionEvent E2,float velocityX,float velocityY) : The user presses the touch screen, moves quickly and releases the screen. E1: the first ACTION_DOWN MotionEvent E2: the first ACTION_DOWN MotionEvent E2: Last ACTION_MOVE MotionEvent velocityX: movement speed on the X axis, pixels per second velocityY: movement speed on the Y axis, pixels per second

  • OnScroll (MotionEvent E1, MotionEvent E2,float distanceX, float distanceY) : To drag events on the screen. This method fires multiple times, either when you drag the view by hand or when you scroll with a cast action. This method fires when the ACTION_MOVE action occurs: After touching the screen with your finger, release onDown—– onScroll—- onScroll—- onScroll—-… —–> onScroll drag onDown—— onScroll—- onScroll—— onFiling The onFling event is triggered!

Code sample
 
GestureDetector.SimpleOnGestureListener myGestureListener = new 
GestureDetector.SimpleOnGestureListener();

 GestureDetector mDetector = new GestureDetector(mContext, mListener);

 monitorView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                mDetector.onTouchEvent(event);
                return false; }});Copy the code

IGestureDetectorMonitor View Abstract interface for gesture monitor

/** * Author: CharlesChen * Time: 2019/5/8. * Desc: View gesture monitor * version: v1.0 */
public interface IGestureDetectorMonitor {

    /** * Phone monitoring */
    IGestureDetector getDetector(a);

    /** * bind listener **@paramMonitorView binds the View */ that you want to listen to
    void bindMonitorView(View monitorView);

    /** * bind listener **@paramMonitorView binds the View * that you want to listen on@paramExternal listener also needs to listen for additional touches */
    void bindMonitorView(View monitorView, final View.OnTouchListener listener);
}
Copy the code

GestureDetectorMonitor View Gesture monitor

/** * Author: CharlesChen * Time: 2019/5/8. * Email: [email protected] * Desc: gesture controller * version: v1.0 */

public abstract class GestureDetectorMonitor implements IGestureDetectorMonitor {

    protected Context mContext;

    public GestureDetectorMonitor(Context context) {
        this.mContext = context;
    }

    public void bindMonitorView(View monitorView) {
        bindMonitorView(monitorView, null);
    }

    public void bindMonitorView(View monitorView, final View.OnTouchListener listener) {
        if (monitorView == null) {
            return;
        }
        monitorView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                onTouchEvent(event);
                if(listener ! =null) {
                    return listener.onTouch(v, event);
                }
                return false; }}); }protected boolean onTouchEvent(MotionEvent event) {
        if(getDetector() ! =null) {
            return getDetector().onTouchEvent(event);
        } else {
            return false; }}}Copy the code

CameraScrollGestureDetectorMonitor sliding zoom monitor

/** * Author: CharlesChen * Time: 2019/5/8. * Email: [email protected] * Desc: sliding zoom monitor * version: v1.0 */

public class CameraScrollGestureDetectorMonitor extends ScrollGestureDetectorMonitor {
    private static final String TAG = "CameraScrollGestureDetectorMonitor";
    private float curRawY = 0;
    private CameraZoomTrigger cameraZoomTrigger;
    private float maxDistance = 1;
    private OnZoomStateListener mZoomStateListener;
    // Start scaling the identifier
    private boolean isStartZoom = false;
    // Whether the last magnification mark is exceeded
    private boolean isZoomHolder = false;
    // Start zoom range 0~1
    private float initialZoom = 0f;

    private GestureDetector.SimpleOnGestureListener myGestureListener = new GestureDetector.SimpleOnGestureListener() {
        private float initialY = 0;
        private float pressHeight = SystemUtils.dip2px(ApplicationController.getApplication(), 80);
        private float triggerHeight = SystemUtils.dip2px(ApplicationController.getApplication(), 40);

        @Override
        public void onLongPress(MotionEvent e) {
            FxLog.d(TAG, " onLongPress " + e.getRawY());
            // Record the start point of the press
            initialY = e.getRawY();
            // Start scaling the identifier
            isStartZoom = true;
            onZoomStart();
            try {// If the long press is triggered, the response to the scroll event will not continue
                Field mInLongPress = GestureDetector.class.getDeclaredField("mInLongPress");
                mInLongPress.setAccessible(true);
                mInLongPress.setBoolean(getDetector(), false);
            } catch (Exception e1) {
                e1.printStackTrace();
            }
            super.onLongPress(e);
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            if(! isStartZoom) {return false;
            }
            curRawY = e2.getRawY();
            FxLog.d(TAG, " onScroll getRawY=" + curRawY);
            // Calculate the sliding distance triggerHeight
            float scrollDistance = initialY - curRawY - triggerHeight;
            // Convert to zoom range 0~1
            float zoomValue = CameraZoomTrigger.range(scrollDistance / (maxDistance - pressHeight));
            // Zoom in or zoom out true zoom in and false zoom out
            boolean isIncrease = distanceY > 0;
            // The zoom range must be larger than the last zoom value to trigger the camera zoom (product logic)
            if (initialZoom <= zoomValue) {
                isZoomHolder = false;
            }
            onZoom(zoomValue, isIncrease);
            return false; }};@Override
    protected boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                // Finger lifts or removes the area to end the zoom
                if (isStartZoom) {
                    onZoomEnd();
                }
                isStartZoom = false;
                break;
        }
        return super.onTouchEvent(event);
    }

    public CameraScrollGestureDetectorMonitor(Context context) {
        super(context);
        setOnGestureListener(myGestureListener);
    }

    public void setScrollMaxDistance(int maxDistance) {
        if (maxDistance <= 0) {
            throw new RuntimeException("MaxDistance cannot be a number less than or equal to 0");
        }
        this.maxDistance = maxDistance;
    }

    public void setCameraZoomTrigger(CameraZoomTrigger cameraZoomTrigger) {
        this.cameraZoomTrigger = cameraZoomTrigger;
    }

    private void onZoomStart(a) {
        if(mZoomStateListener ! =null) {
            mZoomStateListener.onZoomStarted();
        }
        if(cameraZoomTrigger ! =null) {// Record the current zoom range when pressed
            initialZoom = cameraZoomTrigger.getCameraZoom();
        }
        isZoomHolder = true;
    }

    private void onZoom(float zoomValue, boolean isIncrease) {
        FxLog.d(TAG, " onZoom zoomValue = " + zoomValue + " isIncrease =" + isIncrease);
        // The zoom range must be larger than the last zoom value to trigger the camera zoom (product logic)
        if(! isZoomHolder && cameraZoomTrigger ! =null) {
            cameraZoomTrigger.setCameraZoom(zoomValue, isIncrease);
        }
        if(mZoomStateListener ! =null) { mZoomStateListener.onZoom(); }}private void onZoomEnd(a) {
        FxLog.d(TAG, " onZoomEnd");
        if(mZoomStateListener ! =null) { mZoomStateListener.onZoomEnded(); }}public void setZoomStateListener(OnZoomStateListener mZoomStateListener) {
        this.mZoomStateListener = mZoomStateListener;
    }

    public interface OnZoomStateListener {
        public void onZoomStarted(a);

        public void onZoom(a);

        public void onZoomEnded(a); }}Copy the code

CameraScaleGestureDetectorMonitor double refers to zoom monitor

/** * Author: CharlesChen * Time: 2019/5/8. * Desc: dual-finger zoom monitor * version: v1.0 */

public class CameraScaleGestureDetectorMonitor extends ScaleGestureDetectorMonitor {
    /** * Maximum magnification */
    public static final float SCALE_MAX = 4.0 f;
    private final int mHeight;
    private final int mWidth;
    /** * defaults to zoom */
    private float initScale = 1.0 f;
    private Matrix scaleMatrix = new Matrix();
    /** * handles the matrix's 9 values */
    private float[] martiXValue = new float[9];
    private final ScaleGestureDetector.SimpleOnScaleGestureListener listener = new ScaleGestureDetector.SimpleOnScaleGestureListener() {
        private static final String TAG = "CameraScaleGesture";

        // Zoom starts
        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            if(cameraZoomTrigger ! =null) {
                // Get the zoom of the current camera
                float zoom = cameraZoomTrigger.getCameraZoom();
                // Convert to scale range 0~1
                float scale = calculateScale(zoom);
                FxLog.d(TAG, " onScaleBegin scale =" + scale + " zoom = " + zoom);
                // Synchronize the current scaling factor
                scaleMatrix.reset();
                scaleMatrix.postScale(scale, scale, mWidth, mHeight);
            }
            if(scaleGestureListener ! =null) {
                scaleGestureListener.onScaleBegin(detector);
            }
            return super.onScaleBegin(detector);
        }

        // End of zoom
        @Override
        public void onScaleEnd(ScaleGestureDetector detector) {
            super.onScaleEnd(detector);
            if(scaleGestureListener ! =null) { scaleGestureListener.onScaleEnd(detector); }}/ / zoom in
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            // Get the current matrix scaling scale
            float scale = getScale();
            // Get the scaling factor
            float scaleFactor = detector.getScaleFactor();
            // Calculate the current scaling range from 0 to 1
            float zoomValue = calculatePercent(scale);
            // Zoom in or zoom out true zoom in and false zoom out
            boolean isIncrease = scaleFactor > 1;
            // Tell the camera to zoom
            if(cameraZoomTrigger ! =null) {
                cameraZoomTrigger.setCameraZoom(zoomValue, isIncrease);
            }
            // Calculate the matrix scaling value
            if (scaleFactor * scale < initScale)
                scaleFactor = initScale / scale;
            if (scaleFactor * scale > SCALE_MAX)
                scaleFactor = SCALE_MAX / scale;
            FxLog.d(TAG, " scale =" + scale + " scaleFactor = " + scaleFactor + " zoomValue= " + zoomValue);
            // Set the zoom scale
            scaleMatrix.postScale(scaleFactor, scaleFactor, mWidth, mHeight);
            if(scaleGestureListener ! =null) {
                scaleGestureListener.onScale(detector);
            }
            return true;
        }

        // Calculate the current scaling range from 0 to 1
        private float calculatePercent(float scale) {
            return CameraZoomTrigger.range((scale - initScale) / (SCALE_MAX - initScale));
        }

        // The interval is converted to a scaling factor
        private float calculateScale(float zoomValue) {
            returnzoomValue * (SCALE_MAX - initScale) + initScale; }};private CameraZoomTrigger cameraZoomTrigger;
    private ScaleGestureDetector.OnScaleGestureListener scaleGestureListener;

    public CameraScaleGestureDetectorMonitor(Context context) {
        super(context);
        mHeight = SystemUtils.getScreenHeight(mContext) / 2;
        mWidth = SystemUtils.getScreenWidth(mContext) / 2;
        setOnGestureListener(listener);
    }

    /** * gets the current matrix scale */
    public float getScale(a) {
        scaleMatrix.getValues(martiXValue);
        return martiXValue[Matrix.MSCALE_X];
    }

    /** * Sets the camera zoom trigger *@paramCameraZoomTrigger cameraZoomTrigger */
    public void setCameraZoomTrigger(CameraZoomTrigger cameraZoomTrigger) {
        this.cameraZoomTrigger = cameraZoomTrigger;
    }

    /** * Set the camera zoom listening *@param scaleGestureListener
     */
    public void setOnScaleGestureListener(ScaleGestureDetector.OnScaleGestureListener scaleGestureListener) {
        this.scaleGestureListener = scaleGestureListener; }}Copy the code

CameraZoomTrigger Trigger for camera zoom

/** * Author: CharlesChen * Time: 2019/5/9. * Desc: trigger for camera zoom * version: v1.0 */

public class CameraZoomTrigger {

    private OnZoomListener listener;

    public CameraZoomTrigger(OnZoomListener listener){
        this.listener = listener;
    }

    public void setCameraZoom(float zoomValue, boolean isIncrease) {
        if(listener ! =null) { listener.onZoom(range(zoomValue), isIncrease); }}public float getCameraZoom(a) {
        if(listener ! =null) {
            return listener.getCameraZoom();
        }
        return 0;
    }

    / * * *@paramValue The value is in the range from 0 to 1 *@return* /
    public static float range(float value) {
        return Math.min(Math.max(value, 0f), 1f);
    }

   public interface OnZoomListener {
        void onZoom(float zoomValue, boolean isIncrease);

       float getCameraZoom(a); }}Copy the code