Skip to content

Instantly share code, notes, and snippets.

@jk2K
Forked from nbarraille/PinchToZoomScaleDetector.java
Last active January 18, 2018 07:17
Show Gist options
  • Save jk2K/67502e1744e081dcfef5 to your computer and use it in GitHub Desktop.
Save jk2K/67502e1744e081dcfef5 to your computer and use it in GitHub Desktop.

Revisions

  1. @tavori tavori revised this gist Mar 10, 2016. 1 changed file with 19 additions and 28 deletions.
    47 changes: 19 additions & 28 deletions ZoomableDraweeView.java
    Original file line number Diff line number Diff line change
    @@ -42,8 +42,8 @@ public class ZoomableDraweeView extends SimpleDraweeView {
    private Matrix mCurrentMatrix;
    private float mMidX;
    private float mMidY;
    private OnZoomChangeListener mZoomChangeListener;
    private OnClickListener mClickListener;
    private OnLongPressListener mLongPressListener;

    public ZoomableDraweeView(Context context) {
    this(context, null);
    @@ -84,20 +84,25 @@ public boolean onScale(ScaleGestureDetector detector) {
    reset();
    }

    if (mZoomChangeListener != null && scaleFactor != 1.0f) {
    mZoomChangeListener.onZoomChange(mCurrentScale);
    }

    return true;
    }
    };
    mScaleDetector = new ScaleGestureDetector(getContext(), mScaleListener);
    mCurrentMatrix = new Matrix();

    GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() {
    public void onLongPress (MotionEvent e) {
    // support long press listener
    if (mLongPressListener != null) {
    mLongPressListener.onLongPress();
    }
    }

    public boolean onSingleTapConfirmed (MotionEvent e) {
    // support single tap listener
    mClickListener.onClick();
    if (mClickListener != null) {
    mClickListener.onClick();
    }
    return true;
    }

    @@ -117,7 +122,6 @@ public boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float
    @Override
    protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    setOnZoomChangeListener(null);
    }

    @Override
    @@ -148,32 +152,19 @@ public void reset() {
    invalidate();
    }

    public void setOnClickListener(OnClickListener listener) {
    mClickListener = listener;
    public void setOnLongPressListener(OnLongPressListener listener) {
    mLongPressListener = listener;
    }

    public interface OnClickListener {
    void onClick();
    public interface OnLongPressListener {
    void onLongPress();
    }

    /**
    * manual call
    * @param listener OnZoomChangeListener
    */
    public void setOnZoomChangeListener(OnZoomChangeListener listener) {
    mZoomChangeListener = listener;
    public void setOnClickListener(OnClickListener listener) {
    mClickListener = listener;
    }

    /**
    * A listener interface for when the zoom scale changes
    */
    public interface OnZoomChangeListener {
    /**
    * Callback method getting triggered when the zoom scale changes.
    * This is not called when the zoom is programmatically reset
    *
    * @param scale the new scale
    */
    void onZoomChange(float scale);
    public interface OnClickListener {
    void onClick();
    }
    }
  2. @tavori tavori revised this gist Mar 10, 2016. 1 changed file with 34 additions and 13 deletions.
    47 changes: 34 additions & 13 deletions ZoomableDraweeView.java
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    package com.xmeise.mm;

    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Matrix;
    @@ -40,7 +42,8 @@ public class ZoomableDraweeView extends SimpleDraweeView {
    private Matrix mCurrentMatrix;
    private float mMidX;
    private float mMidY;
    private OnZoomChangeListener onZoomChangeListener;
    private OnZoomChangeListener mZoomChangeListener;
    private OnClickListener mClickListener;

    public ZoomableDraweeView(Context context) {
    this(context, null);
    @@ -52,6 +55,7 @@ public ZoomableDraweeView(Context context, AttributeSet attrs) {

    public ZoomableDraweeView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

    init();
    }

    @@ -80,8 +84,8 @@ public boolean onScale(ScaleGestureDetector detector) {
    reset();
    }

    if (onZoomChangeListener != null && scaleFactor != 1.0f) {
    onZoomChangeListener.onZoomChange(mCurrentScale);
    if (mZoomChangeListener != null && scaleFactor != 1.0f) {
    mZoomChangeListener.onZoomChange(mCurrentScale);
    }

    return true;
    @@ -91,6 +95,12 @@ public boolean onScale(ScaleGestureDetector detector) {
    mCurrentMatrix = new Matrix();

    GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() {
    public boolean onSingleTapConfirmed (MotionEvent e) {
    // support single tap listener
    mClickListener.onClick();
    return true;
    }

    public boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
    // support drag
    // disable drag when normal scale
    @@ -104,14 +114,6 @@ public boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float
    mGestureDetector = new GestureDetector(getContext(), mGestureListener);
    }

    /**
    * manual call
    * @param listener OnZoomChangeListener
    */
    public void setOnZoomChangeListener(OnZoomChangeListener listener) {
    onZoomChangeListener = listener;
    }

    @Override
    protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    @@ -128,9 +130,12 @@ protected void onDraw(@NonNull Canvas canvas) {

    @Override
    public boolean onTouchEvent(MotionEvent event) {
    mGestureDetector.onTouchEvent(event);
    mScaleDetector.onTouchEvent(event);
    if (!mScaleDetector.isInProgress()) {
    mGestureDetector.onTouchEvent(event);
    }

    return mScaleDetector.onTouchEvent(event) || super.onTouchEvent(event);
    return true;
    }

    /**
    @@ -143,6 +148,22 @@ public void reset() {
    invalidate();
    }

    public void setOnClickListener(OnClickListener listener) {
    mClickListener = listener;
    }

    public interface OnClickListener {
    void onClick();
    }

    /**
    * manual call
    * @param listener OnZoomChangeListener
    */
    public void setOnZoomChangeListener(OnZoomChangeListener listener) {
    mZoomChangeListener = listener;
    }

    /**
    * A listener interface for when the zoom scale changes
    */
  3. @tavori tavori renamed this gist Dec 16, 2015. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  4. @tavori tavori revised this gist Dec 16, 2015. 1 changed file with 53 additions and 38 deletions.
    91 changes: 53 additions & 38 deletions PinchToZoomScaleDetector.java
    Original file line number Diff line number Diff line change
    @@ -1,18 +1,29 @@
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Matrix;
    import android.support.annotation.NonNull;
    import android.util.AttributeSet;
    import android.view.GestureDetector;
    import android.view.MotionEvent;
    import android.view.ScaleGestureDetector;

    import com.facebook.drawee.view.SimpleDraweeView;

    /*
    * The MIT License (MIT)
    *
    * Copyright (c) 2015 - Nathan Barraille
    * Copyright (c) 2015 - Nathan Barraille, jk2K
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy
    * of this software and associated documentation files (the "Software"), to deal
    * in the Software without restriction, including without limitation the rights
    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    * copies of the Software, and to permit persons to whom the Software is
    * furnished to do so, subject to the following conditions:
    *
    *
    * The above copyright notice and this permission notice shall be included in all
    * copies or substantial portions of the Software.
    *
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    @@ -21,41 +32,31 @@
    * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    * SOFTWARE.
    */
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Matrix;
    import android.support.annotation.NonNull;
    import android.support.annotation.Nullable;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.ScaleGestureDetector;

    import com.facebook.drawee.view.SimpleDraweeView;

    /**
    * A SimpleDraweeView that supports Pinch to zoom.
    */
    public class PinchToZoomDraweeView extends SimpleDraweeView {
    private final ScaleGestureDetector mScaleDetector;
    private final ScaleGestureDetector.OnScaleGestureListener mScaleListener;
    public class ZoomableDraweeView extends SimpleDraweeView {
    private ScaleGestureDetector mScaleDetector;
    private GestureDetector mGestureDetector;

    private float mCurrentScale;
    private final Matrix mCurrentMatrix;
    private float mCurrentScale = 1.0f;
    private Matrix mCurrentMatrix;
    private float mMidX;
    private float mMidY;
    @Nullable private OnZoomChangeListener mListener;
    private OnZoomChangeListener onZoomChangeListener;

    public PinchToZoomDraweeView(Context context) {
    public ZoomableDraweeView(Context context) {
    this(context, null);
    }

    public PinchToZoomDraweeView(Context context, AttributeSet attrs) {
    public ZoomableDraweeView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
    }

    public PinchToZoomDraweeView(Context context, AttributeSet attrs, int defStyle) {
    public ZoomableDraweeView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    mScaleListener = new ScaleGestureDetector.SimpleOnScaleGestureListener() {
    init();
    }

    private void init() {
    ScaleGestureDetector.OnScaleGestureListener mScaleListener = new ScaleGestureDetector.SimpleOnScaleGestureListener() {
    @Override
    public boolean onScale(ScaleGestureDetector detector) {
    float scaleFactor = detector.getScaleFactor();
    @@ -71,26 +72,44 @@ public boolean onScale(ScaleGestureDetector detector) {
    mMidY = getHeight() / 2.0f;
    }
    mCurrentScale = newScale;
    // support pinch zoom
    mCurrentMatrix.postScale(scaleFactor, scaleFactor, mMidX, mMidY);
    invalidate();
    } else {
    scaleFactor = 1.0f / mCurrentScale;
    reset();
    }

    if (mListener != null && scaleFactor != 1.0f) {
    mListener.onZoomChange(mCurrentScale);
    if (onZoomChangeListener != null && scaleFactor != 1.0f) {
    onZoomChangeListener.onZoomChange(mCurrentScale);
    }

    return true;
    }
    };
    mScaleDetector = new ScaleGestureDetector(getContext(), mScaleListener);
    mCurrentMatrix = new Matrix();

    GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() {
    public boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
    // support drag
    // disable drag when normal scale
    if (mCurrentScale > 1.0f) {
    mCurrentMatrix.postTranslate(-distanceX, -distanceY);
    invalidate();
    }
    return true;
    }
    };
    mGestureDetector = new GestureDetector(getContext(), mGestureListener);
    }

    /**
    * manual call
    * @param listener OnZoomChangeListener
    */
    public void setOnZoomChangeListener(OnZoomChangeListener listener) {
    mListener = listener;
    onZoomChangeListener = listener;
    }

    @Override
    @@ -109,14 +128,9 @@ protected void onDraw(@NonNull Canvas canvas) {

    @Override
    public boolean onTouchEvent(MotionEvent event) {
    return mScaleDetector.onTouchEvent(event) || super.onTouchEvent(event);
    }
    mGestureDetector.onTouchEvent(event);

    /**
    * Resets the zoom on that view
    */
    public void resetZoom() {
    reset();
    return mScaleDetector.onTouchEvent(event) || super.onTouchEvent(event);
    }

    /**
    @@ -136,8 +150,9 @@ public interface OnZoomChangeListener {
    /**
    * Callback method getting triggered when the zoom scale changes.
    * This is not called when the zoom is programmatically reset
    *
    * @param scale the new scale
    */
    public void onZoomChange(float scale);
    void onZoomChange(float scale);
    }
    }
  5. @nbarraille nbarraille revised this gist Jun 18, 2015. 1 changed file with 23 additions and 0 deletions.
    23 changes: 23 additions & 0 deletions PinchToZoomScaleDetector.java
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,26 @@
    /*
    * The MIT License (MIT)
    *
    * Copyright (c) 2015 - Nathan Barraille
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy
    * of this software and associated documentation files (the "Software"), to deal
    * in the Software without restriction, including without limitation the rights
    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    * copies of the Software, and to permit persons to whom the Software is
    * furnished to do so, subject to the following conditions:
    *
    * The above copyright notice and this permission notice shall be included in all
    * copies or substantial portions of the Software.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    * SOFTWARE.
    */
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Matrix;
  6. @nbarraille nbarraille revised this gist Apr 7, 2015. 1 changed file with 0 additions and 2 deletions.
    2 changes: 0 additions & 2 deletions PinchToZoomScaleDetector.java
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,3 @@
    package net.slideshare.mobile.ui.widgets;

    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Matrix;
  7. @nbarraille nbarraille created this gist Apr 7, 2015.
    122 changes: 122 additions & 0 deletions PinchToZoomScaleDetector.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,122 @@
    package net.slideshare.mobile.ui.widgets;

    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Matrix;
    import android.support.annotation.NonNull;
    import android.support.annotation.Nullable;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.ScaleGestureDetector;

    import com.facebook.drawee.view.SimpleDraweeView;

    /**
    * A SimpleDraweeView that supports Pinch to zoom.
    */
    public class PinchToZoomDraweeView extends SimpleDraweeView {
    private final ScaleGestureDetector mScaleDetector;
    private final ScaleGestureDetector.OnScaleGestureListener mScaleListener;

    private float mCurrentScale;
    private final Matrix mCurrentMatrix;
    private float mMidX;
    private float mMidY;
    @Nullable private OnZoomChangeListener mListener;

    public PinchToZoomDraweeView(Context context) {
    this(context, null);
    }

    public PinchToZoomDraweeView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
    }

    public PinchToZoomDraweeView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    mScaleListener = new ScaleGestureDetector.SimpleOnScaleGestureListener() {
    @Override
    public boolean onScale(ScaleGestureDetector detector) {
    float scaleFactor = detector.getScaleFactor();
    float newScale = mCurrentScale * scaleFactor;
    // Prevent from zooming out more than original
    if (newScale > 1.0f) {
    // We initialize this lazily so that we don't have to register (and force the user
    // to unregister) a global layout listener on the view.
    if (mMidX == 0.0f) {
    mMidX = getWidth() / 2.0f;
    }
    if (mMidY == 0.0f) {
    mMidY = getHeight() / 2.0f;
    }
    mCurrentScale = newScale;
    mCurrentMatrix.postScale(scaleFactor, scaleFactor, mMidX, mMidY);
    invalidate();
    } else {
    scaleFactor = 1.0f / mCurrentScale;
    reset();
    }

    if (mListener != null && scaleFactor != 1.0f) {
    mListener.onZoomChange(mCurrentScale);
    }

    return true;
    }
    };
    mScaleDetector = new ScaleGestureDetector(getContext(), mScaleListener);
    mCurrentMatrix = new Matrix();
    }

    public void setOnZoomChangeListener(OnZoomChangeListener listener) {
    mListener = listener;
    }

    @Override
    protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    setOnZoomChangeListener(null);
    }

    @Override
    protected void onDraw(@NonNull Canvas canvas) {
    int saveCount = canvas.save();
    canvas.concat(mCurrentMatrix);
    super.onDraw(canvas);
    canvas.restoreToCount(saveCount);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
    return mScaleDetector.onTouchEvent(event) || super.onTouchEvent(event);
    }

    /**
    * Resets the zoom on that view
    */
    public void resetZoom() {
    reset();
    }

    /**
    * Resets the zoom of the attached image.
    * This has no effect if the image has been destroyed
    */
    public void reset() {
    mCurrentMatrix.reset();
    mCurrentScale = 1.0f;
    invalidate();
    }

    /**
    * A listener interface for when the zoom scale changes
    */
    public interface OnZoomChangeListener {
    /**
    * Callback method getting triggered when the zoom scale changes.
    * This is not called when the zoom is programmatically reset
    * @param scale the new scale
    */
    public void onZoomChange(float scale);
    }
    }