@@ -143,6 +143,7 @@ public class SubsamplingScaleImageView extends View {
143143 // Gesture detection settings
144144 private boolean panEnabled = true ;
145145 private boolean zoomEnabled = true ;
146+ private boolean quickScaleEnabled = true ;
146147
147148 // Double tap zoom behaviour
148149 private float doubleTapZoomScale = 1F ;
@@ -262,6 +263,9 @@ public boolean handleMessage(Message message) {
262263 if (typedAttr .hasValue (styleable .SubsamplingScaleImageView_zoomEnabled )) {
263264 setZoomEnabled (typedAttr .getBoolean (styleable .SubsamplingScaleImageView_zoomEnabled , true ));
264265 }
266+ if (typedAttr .hasValue (styleable .SubsamplingScaleImageView_quickScaleEnabled )) {
267+ setQuickScaleEnabled (typedAttr .getBoolean (styleable .SubsamplingScaleImageView_quickScaleEnabled , true ));
268+ }
265269 if (typedAttr .hasValue (styleable .SubsamplingScaleImageView_tileBackgroundColor )) {
266270 setTileBackgroundColor (typedAttr .getColor (styleable .SubsamplingScaleImageView_tileBackgroundColor , Color .argb (0 , 0 , 0 , 0 )));
267271 }
@@ -472,21 +476,28 @@ public boolean onSingleTapConfirmed(MotionEvent e) {
472476 @ Override
473477 public boolean onDoubleTap (MotionEvent e ) {
474478 if (zoomEnabled && readySent && vTranslate != null ) {
475- vCenterStart = new PointF (e .getX (), e .getY ());
476- vTranslateStart = new PointF (vTranslate .x , vTranslate .y );
477- scaleStart = scale ;
478-
479- isQuickScaling = true ;
480- isZooming = true ;
481- quickScaleCenter = viewToSourceCoord (vCenterStart );
482- quickScaleLastDistance = -1F ;
483- quickScaleLastPoint = new PointF (quickScaleCenter .x , quickScaleCenter .y );
484- quickScaleMoved = false ;
485-
479+ // Hacky solution for #15 - after a double tap the GestureDetector gets in a state
480+ // where the next fling is ignored, so here we replace it with a new one.
486481 setGestureDetector (context );
487-
488- // We really want to get events in onTouchEvent after this, so don't return true
489- return false ;
482+ if (quickScaleEnabled ) {
483+ // Store quick scale params. This will become either a double tap zoom or a
484+ // quick scale depending on whether the user swipes.
485+ vCenterStart = new PointF (e .getX (), e .getY ());
486+ vTranslateStart = new PointF (vTranslate .x , vTranslate .y );
487+ scaleStart = scale ;
488+ isQuickScaling = true ;
489+ isZooming = true ;
490+ quickScaleCenter = viewToSourceCoord (vCenterStart );
491+ quickScaleLastDistance = -1F ;
492+ quickScaleLastPoint = new PointF (quickScaleCenter .x , quickScaleCenter .y );
493+ quickScaleMoved = false ;
494+ // We need to get events in onTouchEvent after this.
495+ return false ;
496+ } else {
497+ // Start double tap zoom animation.
498+ doubleTapZoom (viewToSourceCoord (new PointF (e .getX (), e .getY ())), new PointF (e .getX (), e .getY ()));
499+ return true ;
500+ }
490501 }
491502 return super .onDoubleTapEvent (e );
492503 }
@@ -731,28 +742,7 @@ public boolean onTouchEvent(@NonNull MotionEvent event) {
731742 if (isQuickScaling ) {
732743 isQuickScaling = false ;
733744 if (!quickScaleMoved ) {
734- if (!panEnabled ) {
735- if (sRequestedCenter != null ) {
736- // With a center specified from code, zoom around that point.
737- quickScaleCenter .x = sRequestedCenter .x ;
738- quickScaleCenter .y = sRequestedCenter .y ;
739- } else {
740- // With no requested center, scale around the image center.
741- quickScaleCenter .x = sWidth ()/2 ;
742- quickScaleCenter .y = sHeight ()/2 ;
743- }
744- }
745- float doubleTapZoomScale = Math .min (maxScale , SubsamplingScaleImageView .this .doubleTapZoomScale );
746- boolean zoomIn = scale <= doubleTapZoomScale * 0.9 ;
747- float targetScale = zoomIn ? doubleTapZoomScale : minScale ();
748- if (doubleTapZoomStyle == ZOOM_FOCUS_CENTER_IMMEDIATE ) {
749- setScaleAndCenter (targetScale , quickScaleCenter );
750- } else if (doubleTapZoomStyle == ZOOM_FOCUS_CENTER || !zoomIn || !panEnabled ) {
751- new AnimationBuilder (targetScale , quickScaleCenter ).withInterruptible (false ).start ();
752- } else if (doubleTapZoomStyle == ZOOM_FOCUS_FIXED ) {
753- new AnimationBuilder (targetScale , quickScaleCenter , vCenterStart ).withInterruptible (false ).start ();
754- }
755- invalidate ();
745+ doubleTapZoom (quickScaleCenter , vCenterStart );
756746 }
757747 }
758748 if (maxTouchCount > 0 && (isZooming || isPanning )) {
@@ -789,6 +779,35 @@ public boolean onTouchEvent(@NonNull MotionEvent event) {
789779 return super .onTouchEvent (event );
790780 }
791781
782+ /**
783+ * Double tap zoom handler triggered from gesture detector or on touch, depending on whether
784+ * quick scale is enabled.
785+ */
786+ private void doubleTapZoom (PointF sCenter , PointF vFocus ) {
787+ if (!panEnabled ) {
788+ if (sRequestedCenter != null ) {
789+ // With a center specified from code, zoom around that point.
790+ sCenter .x = sRequestedCenter .x ;
791+ sCenter .y = sRequestedCenter .y ;
792+ } else {
793+ // With no requested center, scale around the image center.
794+ sCenter .x = sWidth ()/2 ;
795+ sCenter .y = sHeight ()/2 ;
796+ }
797+ }
798+ float doubleTapZoomScale = Math .min (maxScale , SubsamplingScaleImageView .this .doubleTapZoomScale );
799+ boolean zoomIn = scale <= doubleTapZoomScale * 0.9 ;
800+ float targetScale = zoomIn ? doubleTapZoomScale : minScale ();
801+ if (doubleTapZoomStyle == ZOOM_FOCUS_CENTER_IMMEDIATE ) {
802+ setScaleAndCenter (targetScale , sCenter );
803+ } else if (doubleTapZoomStyle == ZOOM_FOCUS_CENTER || !zoomIn || !panEnabled ) {
804+ new AnimationBuilder (targetScale , sCenter ).withInterruptible (false ).start ();
805+ } else if (doubleTapZoomStyle == ZOOM_FOCUS_FIXED ) {
806+ new AnimationBuilder (targetScale , sCenter , vFocus ).withInterruptible (false ).start ();
807+ }
808+ invalidate ();
809+ }
810+
792811 /**
793812 * Draw method should not be called until the view has dimensions so the first calls are used as triggers to calculate
794813 * the scaling and tiling required. Once the view is setup, tiles are displayed as they are loaded.
@@ -2174,6 +2193,20 @@ public final void setZoomEnabled(boolean zoomEnabled) {
21742193 this .zoomEnabled = zoomEnabled ;
21752194 }
21762195
2196+ /**
2197+ * Returns true if double tap & swipe to zoom is enabled.
2198+ */
2199+ public final boolean isQuickScaleEnabled () {
2200+ return quickScaleEnabled ;
2201+ }
2202+
2203+ /**
2204+ * Enable or disable double tap & swipe to zoom.
2205+ */
2206+ public final void setQuickScaleEnabled (boolean quickScaleEnabled ) {
2207+ this .quickScaleEnabled = quickScaleEnabled ;
2208+ }
2209+
21772210 /**
21782211 * Returns true if pan gesture detection is enabled.
21792212 */
0 commit comments