فهرست منبع

feat: 缩放控件支持单击

DoggyZhang 2 ماه پیش
والد
کامیت
e5ad586a3b

+ 19 - 0
app/build.gradle

@@ -67,6 +67,25 @@ dependencies {
     // android
     implementation libs.android.material
 
+    //fresco
+    implementation(libs.fresco) {
+        exclude group: 'com.facebook.fresco', module: 'drawee'
+    }
+    implementation libs.fresco.imagepipeline
+    implementation(libs.fresco.animated.base) {
+        exclude group: 'com.facebook.fresco', module: 'drawee'
+    }
+    implementation libs.fresco.webpsupport
+    implementation(libs.fresco.animated.webp) {
+        exclude group: 'com.facebook.fresco', module: 'drawee'
+    }
+    implementation(libs.fresco.animated.gif) {
+        exclude group: 'com.facebook.fresco', module: 'drawee'
+    }
+    implementation(libs.fresco.middleware) {
+        exclude group: 'com.facebook.fresco', module: 'drawee'
+    }
+
     implementation project(":frame:zero")
     implementation project(":frame:base")
     implementation project(":frame:aab")

+ 64 - 0
app/src/main/java/com/adealink/frame/image/ImageActivity.kt

@@ -1,10 +1,22 @@
 package com.adealink.frame.image
 
+import android.graphics.drawable.Animatable
 import android.os.Bundle
+import android.util.Log
+import android.webkit.URLUtil
 import androidx.appcompat.app.AppCompatActivity
 import com.adealink.frame.R
 import com.adealink.frame.image.view.NetworkImageView
+import com.adealink.frame.image.view.zoomable.IExtraListener
+import com.adealink.frame.image.view.zoomable.ZoomableDraweeView
+import com.adealink.frame.util.ImageUtil
+import com.facebook.drawee.backends.pipeline.Fresco
+import com.facebook.drawee.controller.BaseControllerListener
+import com.facebook.drawee.drawable.ProgressBarDrawable
 import com.facebook.drawee.drawable.ScalingUtils
+import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder
+import com.facebook.drawee.interfaces.DraweeController
+import com.facebook.imagepipeline.image.ImageInfo
 
 class ImageActivity : AppCompatActivity() {
 
@@ -18,6 +30,58 @@ class ImageActivity : AppCompatActivity() {
             setDefaultImageResId(R.mipmap.room_micseat_seat_unlock_ic)
         }
 
+        val urlPath = "https://im.sdk.qcloud.com/download/tuikit-resource/conversation-backgroundImage/backgroundImage_1_full.png"
+
+        findViewById<ZoomableDraweeView>(R.id.v_zoom)?.let {
+            val ctrl: DraweeController = Fresco.newDraweeControllerBuilder()
+                .setUri(
+                    if (URLUtil.isNetworkUrl(urlPath)) {
+                        urlPath
+                    } else if (urlPath.startsWith("content:") || urlPath.startsWith("file:")){
+                        urlPath
+                    } else {
+                        ImageUtil.getImageUri(urlPath)?.toString()
+                    }
+                ).setTapToRetryEnabled(true)
+                .setControllerListener(
+                    object : BaseControllerListener<ImageInfo>() {
+                        override fun onFinalImageSet(
+                            id: String?,
+                            imageInfo: ImageInfo?,
+                            animatable: Animatable?
+                        ) {
+                            super.onFinalImageSet(id, imageInfo, animatable)
+                        }
+
+                        override fun onFailure(id: String?, throwable: Throwable?) {
+                            super.onFailure(id, throwable)
+                        }
+                    }
+                )
+                .build()
+            it.setExtraListener(object : IExtraListener {
+                override fun onLongClick() {
+                    Log.d("tag_image", "onLongClick")
+                }
+
+                override fun onSwipeDown() {
+                    Log.d("tag_image", "onSwipeDown")
+                }
+
+                override fun onTap() {
+                    Log.d("tag_image", "onTap")
+                }
+
+            })
+            val hierarchy = GenericDraweeHierarchyBuilder(resources)
+                .setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
+                .setProgressBarImage(ProgressBarDrawable())
+                .build()
+            it.controller = ctrl
+            it.hierarchy = hierarchy
+        }
+
+
 //        findViewById<NetworkImageView>(R.id.v_image2).apply {
 //            hierarchy.actualImageScaleType = ScalingUtils.ScaleType.FIT_CENTER
 //            setDefaultImageResId(R.mipmap.room_micseat_seat_unlock_ic)

+ 4 - 0
app/src/main/res/layout/activity_image.xml

@@ -11,6 +11,10 @@
         android:layout_height="200dp"
         android:scaleType="fitCenter" />
 
+    <com.adealink.frame.image.view.zoomable.ZoomableDraweeView
+        android:id="@+id/v_zoom"
+        android:layout_width="300dp"
+        android:layout_height="300dp"/>
 
 <!--    <com.adealink.frame.image.view.NetworkImageView-->
 <!--        android:id="@+id/v_image2"-->

+ 1 - 1
frame/bom/build.gradle

@@ -6,7 +6,7 @@ plugins {
 ext {
     GROUP_ID = 'com.wenext.android'
     ARTIFACT_ID = 'frame-bom'
-    VERSION = '6.2.1'
+    VERSION = '6.2.2'
 }
 
 dependencies {

+ 1 - 1
frame/image/build.gradle

@@ -7,7 +7,7 @@ plugins {
 ext {
     GROUP_ID = 'com.wenext.android'
     ARTIFACT_ID = 'frame-image'
-    VERSION = '6.0.7'
+    VERSION = '6.0.8'
 }
 
 if (project.FRAME_DEBUG != "true") {

+ 271 - 238
frame/image/src/main/java/com/adealink/frame/image/view/zoomable/DefaultZoomableController.java

@@ -21,263 +21,296 @@ import android.view.MotionEvent;
  * Zoomable controller that calculates transformation based on touch events.
  */
 public class DefaultZoomableController
-    implements ZoomableController, TransformGestureDetector.Listener {
-
-  private TransformGestureDetector mGestureDetector;
-
-  private Listener mListener = null;
-
-  private boolean mIsEnabled = false;
-  private boolean mIsRotationEnabled = false;
-  private boolean mIsScaleEnabled = true;
-  private boolean mIsTranslationEnabled = true;
-
-  private float mMinScaleFactor = 1.0f;
-
-  private final RectF mViewBounds = new RectF();
-  private final RectF mImageBounds = new RectF();
-  private final RectF mTransformedImageBounds = new RectF();
-  private final Matrix mPreviousTransform = new Matrix();
-  private final Matrix mActiveTransform = new Matrix();
-  private final Matrix mActiveTransformInverse = new Matrix();
-  private final float[] mTempValues = new float[9];
-
-  public DefaultZoomableController(TransformGestureDetector gestureDetector) {
-    mGestureDetector = gestureDetector;
-    mGestureDetector.setListener(this);
-  }
-
-  public static DefaultZoomableController newInstance() {
-    return new DefaultZoomableController(TransformGestureDetector.newInstance());
-  }
-
-  @Override
-  public void setListener(Listener listener) {
-    mListener = listener;
-  }
-
-  /** Rests the controller. */
-  public void reset() {
-    mGestureDetector.reset();
-    mPreviousTransform.reset();
-    mActiveTransform.reset();
-  }
-
-  /** Sets whether the controller is enabled or not. */
-  @Override
-  public void setEnabled(boolean enabled) {
-    mIsEnabled = enabled;
-    if (!enabled) {
-      reset();
+        implements ZoomableController, TransformGestureDetector.Listener {
+
+    private TransformGestureDetector mGestureDetector;
+
+    private Listener mListener = null;
+
+    private boolean mIsEnabled = false;
+    private boolean mIsRotationEnabled = false;
+    private boolean mIsScaleEnabled = true;
+    private boolean mIsTranslationEnabled = true;
+
+    private float mMinScaleFactor = 1.0f;
+
+    private final RectF mViewBounds = new RectF();
+    private final RectF mImageBounds = new RectF();
+    private final RectF mTransformedImageBounds = new RectF();
+    private final Matrix mPreviousTransform = new Matrix();
+    private final Matrix mActiveTransform = new Matrix();
+    private final Matrix mActiveTransformInverse = new Matrix();
+    private final float[] mTempValues = new float[9];
+
+    public DefaultZoomableController(TransformGestureDetector gestureDetector) {
+        mGestureDetector = gestureDetector;
+        mGestureDetector.setListener(this);
+    }
+
+    public static DefaultZoomableController newInstance() {
+        return new DefaultZoomableController(TransformGestureDetector.newInstance());
+    }
+
+    @Override
+    public void setListener(Listener listener) {
+        mListener = listener;
+    }
+
+    /**
+     * Rests the controller.
+     */
+    public void reset() {
+        mGestureDetector.reset();
+        mPreviousTransform.reset();
+        mActiveTransform.reset();
+    }
+
+    /**
+     * Sets whether the controller is enabled or not.
+     */
+    @Override
+    public void setEnabled(boolean enabled) {
+        mIsEnabled = enabled;
+        if (!enabled) {
+            reset();
+        }
+    }
+
+    /**
+     * Returns whether the controller is enabled or not.
+     */
+    @Override
+    public boolean isEnabled() {
+        return mIsEnabled;
+    }
+
+    /**
+     * Sets whether the rotation gesture is enabled or not.
+     */
+    public void setRotationEnabled(boolean enabled) {
+        mIsRotationEnabled = enabled;
+    }
+
+    /**
+     * Gets whether the rotation gesture is enabled or not.
+     */
+    public boolean isRotationEnabled() {
+        return mIsRotationEnabled;
+    }
+
+    /**
+     * Sets whether the scale gesture is enabled or not.
+     */
+    public void setScaleEnabled(boolean enabled) {
+        mIsScaleEnabled = enabled;
+    }
+
+    /**
+     * Gets whether the scale gesture is enabled or not.
+     */
+    public boolean isScaleEnabled() {
+        return mIsScaleEnabled;
     }
-  }
-
-  /** Returns whether the controller is enabled or not. */
-  @Override
-  public boolean isEnabled() {
-    return mIsEnabled;
-  }
-
-  /** Sets whether the rotation gesture is enabled or not. */
-  public void setRotationEnabled(boolean enabled) {
-    mIsRotationEnabled = enabled;
-  }
-
-  /** Gets whether the rotation gesture is enabled or not. */
-  public boolean isRotationEnabled() {
-    return  mIsRotationEnabled;
-  }
-
-  /** Sets whether the scale gesture is enabled or not. */
-  public void setScaleEnabled(boolean enabled) {
-    mIsScaleEnabled = enabled;
-  }
-
-  /** Gets whether the scale gesture is enabled or not. */
-  public boolean isScaleEnabled() {
-    return  mIsScaleEnabled;
-  }
-
-  /** Sets whether the translation gesture is enabled or not. */
-  public void setTranslationEnabled(boolean enabled) {
-    mIsTranslationEnabled = enabled;
-  }
-
-  /** Gets whether the translations gesture is enabled or not. */
-  public boolean isTranslationEnabled() {
-    return  mIsTranslationEnabled;
-  }
-
-  /** Sets the image bounds before zoomable transformation is applied. */
-  @Override
-  public void setImageBounds(RectF imageBounds) {
-    mImageBounds.set(imageBounds);
-  }
-
-  /** Sets the view bounds. */
-  @Override
-  public void setViewBounds(RectF viewBounds) {
-    mViewBounds.set(viewBounds);
-  }
-
-  /**
-   * Maps point from the view's to the image's relative coordinate system.
-   * This takes into account the zoomable transformation.
-   */
-  public PointF mapViewToImage(PointF viewPoint) {
-    float[] points = mTempValues;
-    points[0] = viewPoint.x;
-    points[1] = viewPoint.y;
-    mActiveTransform.invert(mActiveTransformInverse);
-    mActiveTransformInverse.mapPoints(points, 0, points, 0, 1);
-    mapAbsoluteToRelative(points, points, 1);
-    return new PointF(points[0], points[1]);
-  }
-
-  /**
-   * Maps point from the image's relative to the view's coordinate system.
-   * This takes into account the zoomable transformation.
-   */
-  public PointF mapImageToView(PointF imagePoint) {
-    float[] points = mTempValues;
-    points[0] = imagePoint.x;
-    points[1] = imagePoint.y;
-    mapRelativeToAbsolute(points, points, 1);
-    mActiveTransform.mapPoints(points, 0, points, 0, 1);
-    return new PointF(points[0], points[1]);
-  }
-
-  /**
-   * Maps array of 2D points from absolute to the image's relative coordinate system,
-   * and writes the transformed points back into the array.
-   * Points are represented by float array of [x0, y0, x1, y1, ...].
-   *
-   * @param destPoints destination array (may be the same as source array)
-   * @param srcPoints source array
-   * @param numPoints number of points to map
-   */
-  private void mapAbsoluteToRelative(float[] destPoints, float[] srcPoints, int numPoints) {
-    for (int i = 0; i < numPoints; i++) {
-      destPoints[i * 2 + 0] = (srcPoints[i * 2 + 0] - mImageBounds.left) / mImageBounds.width();
-      destPoints[i * 2 + 1] = (srcPoints[i * 2 + 1] - mImageBounds.top) / mImageBounds.height();
+
+    /**
+     * Sets whether the translation gesture is enabled or not.
+     */
+    public void setTranslationEnabled(boolean enabled) {
+        mIsTranslationEnabled = enabled;
+    }
+
+    /**
+     * Gets whether the translations gesture is enabled or not.
+     */
+    public boolean isTranslationEnabled() {
+        return mIsTranslationEnabled;
+    }
+
+    /**
+     * Sets the image bounds before zoomable transformation is applied.
+     */
+    @Override
+    public void setImageBounds(RectF imageBounds) {
+        mImageBounds.set(imageBounds);
+    }
+
+    /**
+     * Sets the view bounds.
+     */
+    @Override
+    public void setViewBounds(RectF viewBounds) {
+        mViewBounds.set(viewBounds);
+    }
+
+    /**
+     * Maps point from the view's to the image's relative coordinate system.
+     * This takes into account the zoomable transformation.
+     */
+    public PointF mapViewToImage(PointF viewPoint) {
+        float[] points = mTempValues;
+        points[0] = viewPoint.x;
+        points[1] = viewPoint.y;
+        mActiveTransform.invert(mActiveTransformInverse);
+        mActiveTransformInverse.mapPoints(points, 0, points, 0, 1);
+        mapAbsoluteToRelative(points, points, 1);
+        return new PointF(points[0], points[1]);
+    }
+
+    /**
+     * Maps point from the image's relative to the view's coordinate system.
+     * This takes into account the zoomable transformation.
+     */
+    public PointF mapImageToView(PointF imagePoint) {
+        float[] points = mTempValues;
+        points[0] = imagePoint.x;
+        points[1] = imagePoint.y;
+        mapRelativeToAbsolute(points, points, 1);
+        mActiveTransform.mapPoints(points, 0, points, 0, 1);
+        return new PointF(points[0], points[1]);
+    }
+
+    /**
+     * Maps array of 2D points from absolute to the image's relative coordinate system,
+     * and writes the transformed points back into the array.
+     * Points are represented by float array of [x0, y0, x1, y1, ...].
+     *
+     * @param destPoints destination array (may be the same as source array)
+     * @param srcPoints  source array
+     * @param numPoints  number of points to map
+     */
+    private void mapAbsoluteToRelative(float[] destPoints, float[] srcPoints, int numPoints) {
+        for (int i = 0; i < numPoints; i++) {
+            destPoints[i * 2 + 0] = (srcPoints[i * 2 + 0] - mImageBounds.left) / mImageBounds.width();
+            destPoints[i * 2 + 1] = (srcPoints[i * 2 + 1] - mImageBounds.top) / mImageBounds.height();
+        }
     }
-  }
-
-  /**
-   * Maps array of 2D points from relative to the image's absolute coordinate system,
-   * and writes the transformed points back into the array
-   * Points are represented by float array of [x0, y0, x1, y1, ...].
-   *
-   * @param destPoints destination array (may be the same as source array)
-   * @param srcPoints source array
-   * @param numPoints number of points to map
-   */
-  private void mapRelativeToAbsolute(float[] destPoints, float[] srcPoints, int numPoints) {
-    for (int i = 0; i < numPoints; i++) {
-      destPoints[i * 2 + 0] = srcPoints[i * 2 + 0] * mImageBounds.width() + mImageBounds.left;
-      destPoints[i * 2 + 1] = srcPoints[i * 2 + 1] * mImageBounds.height() + mImageBounds.top;
+
+    /**
+     * Maps array of 2D points from relative to the image's absolute coordinate system,
+     * and writes the transformed points back into the array
+     * Points are represented by float array of [x0, y0, x1, y1, ...].
+     *
+     * @param destPoints destination array (may be the same as source array)
+     * @param srcPoints  source array
+     * @param numPoints  number of points to map
+     */
+    private void mapRelativeToAbsolute(float[] destPoints, float[] srcPoints, int numPoints) {
+        for (int i = 0; i < numPoints; i++) {
+            destPoints[i * 2 + 0] = srcPoints[i * 2 + 0] * mImageBounds.width() + mImageBounds.left;
+            destPoints[i * 2 + 1] = srcPoints[i * 2 + 1] * mImageBounds.height() + mImageBounds.top;
+        }
     }
-  }
-
-  /**
-   * Gets the zoomable transformation
-   * Internal matrix is exposed for performance reasons and is not to be modified by the callers.
-   */
-  @Override
-  public Matrix getTransform() {
-    return mActiveTransform;
-  }
-
-  /** Notifies controller of the received touch event.  */
-  @Override
-  public boolean onTouchEvent(MotionEvent event) {
-    if (mIsEnabled) {
-      return mGestureDetector.onTouchEvent(event);
+
+    /**
+     * Gets the zoomable transformation
+     * Internal matrix is exposed for performance reasons and is not to be modified by the callers.
+     */
+    @Override
+    public Matrix getTransform() {
+        return mActiveTransform;
     }
-    return false;
-  }
 
-  /* TransformGestureDetector.Listener methods  */
+    /**
+     * Notifies controller of the received touch event.
+     */
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (mIsEnabled) {
+            return mGestureDetector.onTouchEvent(event);
+        }
+        return false;
+    }
 
-  @Override
-  public void onGestureBegin(TransformGestureDetector detector) {
-  }
+    /* TransformGestureDetector.Listener methods  */
 
-  @Override
-  public void onGestureUpdate(TransformGestureDetector detector) {
-    mActiveTransform.set(mPreviousTransform);
-    if (mIsRotationEnabled) {
-      float angle = detector.getRotation() * (float) (180 / Math.PI);
-      mActiveTransform.postRotate(angle, detector.getPivotX(), detector.getPivotY());
+    @Override
+    public void onGestureBegin(TransformGestureDetector detector) {
     }
-    if (mIsScaleEnabled) {
-      float scale = detector.getScale();
-      mActiveTransform.postScale(scale, scale, detector.getPivotX(), detector.getPivotY());
+
+    @Override
+    public void onGestureUpdate(TransformGestureDetector detector) {
+        mActiveTransform.set(mPreviousTransform);
+        if (mIsRotationEnabled) {
+            float angle = detector.getRotation() * (float) (180 / Math.PI);
+            mActiveTransform.postRotate(angle, detector.getPivotX(), detector.getPivotY());
+        }
+        if (mIsScaleEnabled) {
+            float scale = detector.getScale();
+            mActiveTransform.postScale(scale, scale, detector.getPivotX(), detector.getPivotY());
+        }
+        limitScale(detector.getPivotX(), detector.getPivotY());
+        if (mIsTranslationEnabled) {
+            mActiveTransform.postTranslate(detector.getTranslationX(), detector.getTranslationY());
+        }
+        limitTranslation();
+        if (mListener != null) {
+            mListener.onTransformChanged(mActiveTransform);
+        }
     }
-    limitScale(detector.getPivotX(), detector.getPivotY());
-    if (mIsTranslationEnabled) {
-      mActiveTransform.postTranslate(detector.getTranslationX(), detector.getTranslationY());
+
+    @Override
+    public void onGestureEnd(TransformGestureDetector detector) {
+        mPreviousTransform.set(mActiveTransform);
     }
-    limitTranslation();
-    if (mListener != null) {
-      mListener.onTransformChanged(mActiveTransform);
+
+    @Override
+    public void onLongClick(MotionEvent event) {
+        if (mListener != null) {
+            mListener.onLongClick();
+        }
     }
-  }
 
-  @Override
-  public void onGestureEnd(TransformGestureDetector detector) {
-    mPreviousTransform.set(mActiveTransform);
-  }
+    @Override
+    public void onSwipeDown() {
+        if (mListener != null) {
+            mListener.onSwipeDown();
+        }
+    }
 
-  @Override
-  public void onLongClick(MotionEvent event) {
-    if (mListener != null) {
-      mListener.onLongClick();
+    @Override
+    public void onTap() {
+        if (mListener != null) {
+            mListener.onTap();
+        }
     }
-  }
 
-  @Override
-  public void onSwipeDown() {
-    if (mListener != null) {
-      mListener.onSwipeDown();
+    /**
+     * Gets the current scale factor.
+     */
+    @Override
+    public float getScaleFactor() {
+        mActiveTransform.getValues(mTempValues);
+        return mTempValues[Matrix.MSCALE_X];
     }
-  }
-
-  /** Gets the current scale factor. */
-  @Override
-  public float getScaleFactor() {
-    mActiveTransform.getValues(mTempValues);
-    return mTempValues[Matrix.MSCALE_X];
-  }
-
-  private void limitScale(float pivotX, float pivotY) {
-    float currentScale = getScaleFactor();
-    if (currentScale < mMinScaleFactor) {
-      float scale = mMinScaleFactor / currentScale;
-      mActiveTransform.postScale(scale, scale, pivotX, pivotY);
+
+    private void limitScale(float pivotX, float pivotY) {
+        float currentScale = getScaleFactor();
+        if (currentScale < mMinScaleFactor) {
+            float scale = mMinScaleFactor / currentScale;
+            mActiveTransform.postScale(scale, scale, pivotX, pivotY);
+        }
     }
-  }
-
-  private void limitTranslation() {
-    RectF bounds = mTransformedImageBounds;
-    bounds.set(mImageBounds);
-    mActiveTransform.mapRect(bounds);
-
-    float offsetLeft = getOffset(bounds.left, bounds.width(), mViewBounds.width());
-    float offsetTop = getOffset(bounds.top, bounds.height(), mViewBounds.height());
-    if (offsetLeft != bounds.left || offsetTop != bounds.top) {
-      mActiveTransform.postTranslate(offsetLeft - bounds.left, offsetTop - bounds.top);
-      mGestureDetector.restartGesture();
+
+    private void limitTranslation() {
+        RectF bounds = mTransformedImageBounds;
+        bounds.set(mImageBounds);
+        mActiveTransform.mapRect(bounds);
+
+        float offsetLeft = getOffset(bounds.left, bounds.width(), mViewBounds.width());
+        float offsetTop = getOffset(bounds.top, bounds.height(), mViewBounds.height());
+        if (offsetLeft != bounds.left || offsetTop != bounds.top) {
+            mActiveTransform.postTranslate(offsetLeft - bounds.left, offsetTop - bounds.top);
+            mGestureDetector.restartGesture();
+        }
     }
-  }
 
-  private float getOffset(float offset, float imageDimension, float viewDimension) {
-    float diff = viewDimension - imageDimension;
-    return (diff > 0) ? diff / 2 : limit(offset, diff, 0);
-  }
+    private float getOffset(float offset, float imageDimension, float viewDimension) {
+        float diff = viewDimension - imageDimension;
+        return (diff > 0) ? diff / 2 : limit(offset, diff, 0);
+    }
 
-  private float limit(float value, float min, float max) {
-    return Math.min(Math.max(min, value), max);
-  }
+    private float limit(float value, float min, float max) {
+        return Math.min(Math.max(min, value), max);
+    }
 
 }

+ 2 - 0
frame/image/src/main/java/com/adealink/frame/image/view/zoomable/IExtraListener.java

@@ -3,4 +3,6 @@ package com.adealink.frame.image.view.zoomable;
 public interface IExtraListener {
     public void onLongClick();
     public void onSwipeDown();
+
+    public void onTap();
 }

+ 39 - 0
frame/image/src/main/java/com/adealink/frame/image/view/zoomable/MultiPointerGestureDetector.java

@@ -59,6 +59,10 @@ public class MultiPointerGestureDetector {
         void onSwipeDown();
     }
 
+    public interface OnTapListener {
+        void onTap();
+    }
+
     private static final int MAX_POINTERS = 2;
     private static final int LONG_PRESS_TIMEOUT = 500; // 长按时间阈值
     private static final int SWIPE_THRESHOLD_DP = 100; // 下滑触发阈值
@@ -84,6 +88,9 @@ public class MultiPointerGestureDetector {
     private boolean mIsSwipingDown;
     private float mSwipeStartY;
 
+
+    private OnTapListener mTapListener;
+
     public MultiPointerGestureDetector() {
         reset();
         // 初始化触摸阈值
@@ -117,6 +124,10 @@ public class MultiPointerGestureDetector {
         mOnSwipeDownListener = listener;
     }
 
+    public void setTapListener(OnTapListener listener){
+        mTapListener = listener;
+    }
+
     /**
      * Resets the component to the initial state.
      */
@@ -211,6 +222,7 @@ public class MultiPointerGestureDetector {
                 // 单指按下时启动长按检测
                 if (event.getPointerCount() == 1) {
                     startLongPressCheck(event);
+                    handleTapEvent(event);
                 }
                 handleMultiPointerEvent(event);
                 break;
@@ -235,6 +247,11 @@ public class MultiPointerGestureDetector {
                 handleSwipeFinish(event);
                 cancelLongPressCheck();
                 handleMultiPointerEvent(event);
+
+                //检查单点点击
+                if (event.getPointerCount() == 1) {
+                    handleTapEvent(event);
+                }
                 break;
 
             case MotionEvent.ACTION_POINTER_DOWN:
@@ -284,6 +301,28 @@ public class MultiPointerGestureDetector {
         mIsSwipingDown = false;
     }
 
+
+    private float mTapX = 0;
+    private float mTapY = 0;
+
+    private void handleTapEvent(final MotionEvent event) {
+        switch (event.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN: {
+                mTapX = event.getX();
+                mTapY = event.getY();
+            }
+            case MotionEvent.ACTION_UP: {
+                float dx = event.getX() - mStartX[0];
+                float dy = event.getY() - mStartY[0];
+                if (dx * dx + dy * dy > mTouchSlop * mTouchSlop) {
+                    if (mTapListener != null) {
+                        mTapListener.onTap();
+                    }
+                }
+            }
+        }
+    }
+
     private void handleMultiPointerEvent(final MotionEvent event) {
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_MOVE:

+ 201 - 160
frame/image/src/main/java/com/adealink/frame/image/view/zoomable/TransformGestureDetector.java

@@ -21,166 +21,207 @@ import android.view.MotionEvent;
  * The instance of this detector is passed to the listeners, so it can be queried
  * for pivot, translation, scale or rotation.
  */
-public class TransformGestureDetector implements MultiPointerGestureDetector.Listener, MultiPointerGestureDetector.OnLongClickListener, MultiPointerGestureDetector.OnSwipeDownListener {
+public class TransformGestureDetector implements MultiPointerGestureDetector.Listener,
+        MultiPointerGestureDetector.OnLongClickListener,
+        MultiPointerGestureDetector.OnSwipeDownListener,
+        MultiPointerGestureDetector.OnTapListener {
+
+    /**
+     * The listener for receiving notifications when gestures occur.
+     */
+    public interface Listener {
+        /**
+         * Responds to the beginning of a gesture.
+         */
+        public void onGestureBegin(TransformGestureDetector detector);
+
+        /**
+         * Responds to the update of a gesture in progress.
+         */
+        public void onGestureUpdate(TransformGestureDetector detector);
+
+        /**
+         * Responds to the end of a gesture.
+         */
+        public void onGestureEnd(TransformGestureDetector detector);
+
+        public void onLongClick(MotionEvent event);
+
+        public void onSwipeDown();
+
+        public void onTap();
+    }
+
+    private final MultiPointerGestureDetector mDetector;
+
+    private Listener mListener = null;
 
-  /** The listener for receiving notifications when gestures occur. */
-  public interface Listener {
-    /** Responds to the beginning of a gesture. */
-    public void onGestureBegin(TransformGestureDetector detector);
+    public TransformGestureDetector(MultiPointerGestureDetector multiPointerGestureDetector) {
+        mDetector = multiPointerGestureDetector;
+        mDetector.setListener(this);
+        mDetector.setOnLongClickListener(this);
+        mDetector.setOnSwipeDownListener(this);
+        mDetector.setTapListener(this);
+    }
+
+    /**
+     * Factory method that creates a new instance of TransformGestureDetector
+     */
+    public static TransformGestureDetector newInstance() {
+        return new TransformGestureDetector(MultiPointerGestureDetector.newInstance());
+    }
 
-    /** Responds to the update of a gesture in progress. */
-    public void onGestureUpdate(TransformGestureDetector detector);
-
-    /** Responds to the end of a gesture. */
-    public void onGestureEnd(TransformGestureDetector detector);
-
-    public void onLongClick(MotionEvent event);
-
-    public void onSwipeDown();
-  }
-
-  private final MultiPointerGestureDetector mDetector;
-
-  private Listener mListener = null;
-
-  public TransformGestureDetector(MultiPointerGestureDetector multiPointerGestureDetector) {
-    mDetector = multiPointerGestureDetector;
-    mDetector.setListener(this);
-    mDetector.setOnLongClickListener(this);
-    mDetector.setOnSwipeDownListener(this);
-  }
-
-  /** Factory method that creates a new instance of TransformGestureDetector */
-  public static TransformGestureDetector newInstance() {
-    return new TransformGestureDetector(MultiPointerGestureDetector.newInstance());
-  }
-
-  /**
-   * Sets the listener.
-   * @param listener listener to set
-   */
-  public void setListener(Listener listener) {
-    mListener = listener;
-  }
-
-  /**
-   * Resets the component to the initial state.
-   */
-  public void reset() {
-    mDetector.reset();
-  }
-
-  /**
-   * Handles the given motion event.
-   * @param event event to handle
-   * @return whether or not the event was handled
-   */
-  public boolean onTouchEvent(final MotionEvent event) {
-    return mDetector.onTouchEvent(event);
-  }
-
-  @Override
-  public void onGestureBegin(MultiPointerGestureDetector detector) {
-    if (mListener != null) {
-      mListener.onGestureBegin(this);
-    }
-  }
-
-  @Override
-  public void onGestureUpdate(MultiPointerGestureDetector detector) {
-    if (mListener != null) {
-      mListener.onGestureUpdate(this);
-    }
-  }
-
-  @Override
-  public void onGestureEnd(MultiPointerGestureDetector detector) {
-    if (mListener != null) {
-      mListener.onGestureEnd(this);
-    }
-  }
-
-  @Override
-  public void onLongClick(MotionEvent event) {
-    if (mListener != null) {
-      mListener.onLongClick(event);
-    }
-  }
-
-  @Override
-  public void onSwipeDown() {
-    if (mListener != null) {
-      mListener.onSwipeDown();
-    }
-  }
-
-  private float calcAverage(float[] arr, int len) {
-    float sum = 0;
-    for (int i = 0; i < len; i++) {
-      sum += arr[i];
-    }
-    return (len > 0) ? sum / len : 0;
-  }
-
-  /** Restarts the current gesture */
-  public void restartGesture() {
-    mDetector.restartGesture();
-  }
-
-  /** Gets whether gesture is in progress or not */
-  public boolean isGestureInProgress() {
-    return mDetector.isGestureInProgress();
-  }
-
-  /** Gets the X coordinate of the pivot point */
-  public float getPivotX() {
-    return calcAverage(mDetector.getStartX(), mDetector.getCount());
-  }
-
-  /** Gets the Y coordinate of the pivot point */
-  public float getPivotY() {
-    return calcAverage(mDetector.getStartY(), mDetector.getCount());
-  }
-
-  /** Gets the X component of the translation */
-  public float getTranslationX() {
-    return calcAverage(mDetector.getCurrentX(), mDetector.getCount()) -
-        calcAverage(mDetector.getStartX(), mDetector.getCount());
-  }
-
-  /** Gets the Y component of the translation */
-  public float getTranslationY() {
-    return calcAverage(mDetector.getCurrentY(), mDetector.getCount()) -
-        calcAverage(mDetector.getStartY(), mDetector.getCount());
-  }
-
-  /** Gets the scale */
-  public float getScale() {
-    if (mDetector.getCount() < 2) {
-      return 1;
-    } else {
-      float startDeltaX = mDetector.getStartX()[1] - mDetector.getStartX()[0];
-      float startDeltaY = mDetector.getStartY()[1] - mDetector.getStartY()[0];
-      float currentDeltaX = mDetector.getCurrentX()[1] - mDetector.getCurrentX()[0];
-      float currentDeltaY = mDetector.getCurrentY()[1] - mDetector.getCurrentY()[0];
-      float startDist = (float) Math.hypot(startDeltaX, startDeltaY);
-      float currentDist = (float) Math.hypot(currentDeltaX, currentDeltaY);
-      return currentDist / startDist;
-    }
-  }
-
-  /** Gets the rotation in radians */
-  public float getRotation() {
-    if (mDetector.getCount() < 2) {
-      return 0;
-    } else {
-      float startDeltaX = mDetector.getStartX()[1] - mDetector.getStartX()[0];
-      float startDeltaY = mDetector.getStartY()[1] - mDetector.getStartY()[0];
-      float currentDeltaX = mDetector.getCurrentX()[1] - mDetector.getCurrentX()[0];
-      float currentDeltaY = mDetector.getCurrentY()[1] - mDetector.getCurrentY()[0];
-      float startAngle = (float) Math.atan2(startDeltaY, startDeltaX);
-      float currentAngle = (float) Math.atan2(currentDeltaY, currentDeltaX);
-      return currentAngle - startAngle;
-    }
-  }
+    /**
+     * Sets the listener.
+     *
+     * @param listener listener to set
+     */
+    public void setListener(Listener listener) {
+        mListener = listener;
+    }
+
+    /**
+     * Resets the component to the initial state.
+     */
+    public void reset() {
+        mDetector.reset();
+    }
+
+    /**
+     * Handles the given motion event.
+     *
+     * @param event event to handle
+     * @return whether or not the event was handled
+     */
+    public boolean onTouchEvent(final MotionEvent event) {
+        return mDetector.onTouchEvent(event);
+    }
+
+    @Override
+    public void onGestureBegin(MultiPointerGestureDetector detector) {
+        if (mListener != null) {
+            mListener.onGestureBegin(this);
+        }
+    }
+
+    @Override
+    public void onGestureUpdate(MultiPointerGestureDetector detector) {
+        if (mListener != null) {
+            mListener.onGestureUpdate(this);
+        }
+    }
+
+    @Override
+    public void onGestureEnd(MultiPointerGestureDetector detector) {
+        if (mListener != null) {
+            mListener.onGestureEnd(this);
+        }
+    }
+
+    @Override
+    public void onLongClick(MotionEvent event) {
+        if (mListener != null) {
+            mListener.onLongClick(event);
+        }
+    }
+
+    @Override
+    public void onSwipeDown() {
+        if (mListener != null) {
+            mListener.onSwipeDown();
+        }
+    }
+
+    @Override
+    public void onTap() {
+        if (mListener != null) {
+            mListener.onTap();
+        }
+    }
+
+    private float calcAverage(float[] arr, int len) {
+        float sum = 0;
+        for (int i = 0; i < len; i++) {
+            sum += arr[i];
+        }
+        return (len > 0) ? sum / len : 0;
+    }
+
+    /**
+     * Restarts the current gesture
+     */
+    public void restartGesture() {
+        mDetector.restartGesture();
+    }
+
+    /**
+     * Gets whether gesture is in progress or not
+     */
+    public boolean isGestureInProgress() {
+        return mDetector.isGestureInProgress();
+    }
+
+    /**
+     * Gets the X coordinate of the pivot point
+     */
+    public float getPivotX() {
+        return calcAverage(mDetector.getStartX(), mDetector.getCount());
+    }
+
+    /**
+     * Gets the Y coordinate of the pivot point
+     */
+    public float getPivotY() {
+        return calcAverage(mDetector.getStartY(), mDetector.getCount());
+    }
+
+    /**
+     * Gets the X component of the translation
+     */
+    public float getTranslationX() {
+        return calcAverage(mDetector.getCurrentX(), mDetector.getCount()) -
+                calcAverage(mDetector.getStartX(), mDetector.getCount());
+    }
+
+    /**
+     * Gets the Y component of the translation
+     */
+    public float getTranslationY() {
+        return calcAverage(mDetector.getCurrentY(), mDetector.getCount()) -
+                calcAverage(mDetector.getStartY(), mDetector.getCount());
+    }
+
+    /**
+     * Gets the scale
+     */
+    public float getScale() {
+        if (mDetector.getCount() < 2) {
+            return 1;
+        } else {
+            float startDeltaX = mDetector.getStartX()[1] - mDetector.getStartX()[0];
+            float startDeltaY = mDetector.getStartY()[1] - mDetector.getStartY()[0];
+            float currentDeltaX = mDetector.getCurrentX()[1] - mDetector.getCurrentX()[0];
+            float currentDeltaY = mDetector.getCurrentY()[1] - mDetector.getCurrentY()[0];
+            float startDist = (float) Math.hypot(startDeltaX, startDeltaY);
+            float currentDist = (float) Math.hypot(currentDeltaX, currentDeltaY);
+            return currentDist / startDist;
+        }
+    }
+
+    /**
+     * Gets the rotation in radians
+     */
+    public float getRotation() {
+        if (mDetector.getCount() < 2) {
+            return 0;
+        } else {
+            float startDeltaX = mDetector.getStartX()[1] - mDetector.getStartX()[0];
+            float startDeltaY = mDetector.getStartY()[1] - mDetector.getStartY()[0];
+            float currentDeltaX = mDetector.getCurrentX()[1] - mDetector.getCurrentX()[0];
+            float currentDeltaY = mDetector.getCurrentY()[1] - mDetector.getCurrentY()[0];
+            float startAngle = (float) Math.atan2(startDeltaY, startDeltaX);
+            float currentAngle = (float) Math.atan2(currentDeltaY, currentDeltaX);
+            return currentAngle - startAngle;
+        }
+    }
 }

+ 2 - 0
frame/image/src/main/java/com/adealink/frame/image/view/zoomable/ZoomableController.java

@@ -37,6 +37,8 @@ public interface ZoomableController {
     public void onLongClick();
 
     public void onSwipeDown();
+
+    public void onTap();
   }
 
   /**

+ 175 - 169
frame/image/src/main/java/com/adealink/frame/image/view/zoomable/ZoomableDraweeView.java

@@ -35,80 +35,79 @@ import com.facebook.drawee.view.DraweeView;
  * DraweeView that has zoomable capabilities.
  * <p>
  * Once the image loads, pinch-to-zoom and translation gestures are enabled.
- *
  */
 public class ZoomableDraweeView extends DraweeView<GenericDraweeHierarchy>
-    implements ZoomableController.Listener {
+        implements ZoomableController.Listener {
 
-  private static final Class<?> TAG = ZoomableDraweeView.class;
+    private static final Class<?> TAG = ZoomableDraweeView.class;
 
-  private static final float HUGE_IMAGE_SCALE_FACTOR_THRESHOLD = 1.1f;
+    private static final float HUGE_IMAGE_SCALE_FACTOR_THRESHOLD = 1.1f;
 
-  private final RectF mImageBounds = new RectF();
-  private final RectF mViewBounds = new RectF();
+    private final RectF mImageBounds = new RectF();
+    private final RectF mViewBounds = new RectF();
 
-  private final ControllerListener mControllerListener = new BaseControllerListener<Object>() {
-    @Override
-    public void onFinalImageSet(
-        String id,
-        @Nullable Object imageInfo,
-        @Nullable Animatable animatable) {
-      ZoomableDraweeView.this.onFinalImageSet();
+    private final ControllerListener mControllerListener = new BaseControllerListener<Object>() {
+        @Override
+        public void onFinalImageSet(
+                String id,
+                @Nullable Object imageInfo,
+                @Nullable Animatable animatable) {
+            ZoomableDraweeView.this.onFinalImageSet();
+        }
+
+        @Override
+        public void onRelease(String id) {
+            ZoomableDraweeView.this.onRelease();
+        }
+    };
+
+    private DraweeController mHugeImageController;
+    private ZoomableController mZoomableController = DefaultZoomableController.newInstance();
+    private IExtraListener mExtraListener;
+
+    public ZoomableDraweeView(Context context) {
+        super(context);
+        init();
+    }
+
+    public ZoomableDraweeView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public ZoomableDraweeView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        init();
+    }
+
+    private void init() {
+        mZoomableController.setListener(this);
+    }
+
+    public void setZoomableController(ZoomableController zoomableController) {
+        Preconditions.checkNotNull(zoomableController);
+        mZoomableController.setListener(null);
+        mZoomableController = zoomableController;
+        mZoomableController.setListener(this);
+    }
+
+    public void setExtraListener(IExtraListener extraListener) {
+        mExtraListener = extraListener;
     }
 
     @Override
-    public void onRelease(String id) {
-      ZoomableDraweeView.this.onRelease();
-    }
-  };
-
-  private DraweeController mHugeImageController;
-  private ZoomableController mZoomableController = DefaultZoomableController.newInstance();
-  private IExtraListener mExtraListener;
-
-  public ZoomableDraweeView(Context context) {
-    super(context);
-    init();
-  }
-
-  public ZoomableDraweeView(Context context, AttributeSet attrs) {
-    super(context, attrs);
-    init();
-  }
-
-  public ZoomableDraweeView(Context context, AttributeSet attrs, int defStyle) {
-    super(context, attrs, defStyle);
-    init();
-  }
-
-  private void init() {
-    mZoomableController.setListener(this);
-  }
-
-  public void setZoomableController(ZoomableController zoomableController) {
-    Preconditions.checkNotNull(zoomableController);
-    mZoomableController.setListener(null);
-    mZoomableController = zoomableController;
-    mZoomableController.setListener(this);
-  }
-
-  public void setExtraListener(IExtraListener extraListener) {
-    mExtraListener = extraListener;
-  }
-
-  @Override
-  public void setController(@Nullable DraweeController controller) {
-    setControllers(controller, null);
-  }
-
-  private void setControllersInternal(
-      @Nullable DraweeController controller,
-      @Nullable DraweeController hugeImageController) {
-    removeControllerListener(getController());
-    addControllerListener(controller);
-    mHugeImageController = hugeImageController;
-    super.setController(controller);
-  }
+    public void setController(@Nullable DraweeController controller) {
+        setControllers(controller, null);
+    }
+
+    private void setControllersInternal(
+            @Nullable DraweeController controller,
+            @Nullable DraweeController hugeImageController) {
+        removeControllerListener(getController());
+        addControllerListener(controller);
+        mHugeImageController = hugeImageController;
+        super.setController(controller);
+    }
 
     /**
      * Sets the controllers for the normal and huge image.
@@ -116,112 +115,119 @@ public class ZoomableDraweeView extends DraweeView<GenericDraweeHierarchy>
      * <p> IMPORTANT: in order to avoid a flicker when switching to the huge image, the huge image
      * controller should have the normal-image-uri set as its low-res-uri.
      *
-     * @param controller controller to be initially used
+     * @param controller          controller to be initially used
      * @param hugeImageController controller to be used after the client starts zooming-in
      */
-  public void setControllers(
-      @Nullable DraweeController controller,
-      @Nullable DraweeController hugeImageController) {
-    setControllersInternal(null, null);
-    mZoomableController.setEnabled(false);
-    setControllersInternal(controller, hugeImageController);
-  }
-
-  private void maybeSetHugeImageController() {
-    if (mHugeImageController != null &&
-        mZoomableController.getScaleFactor() > HUGE_IMAGE_SCALE_FACTOR_THRESHOLD) {
-      setControllersInternal(mHugeImageController, null);
-    }
-  }
-
-  private void removeControllerListener(DraweeController controller) {
-    if (controller instanceof AbstractDraweeController) {
-      ((AbstractDraweeController) controller)
-          .removeControllerListener(mControllerListener);
-    }
-  }
-
-  private void addControllerListener(DraweeController controller) {
-    if (controller instanceof AbstractDraweeController) {
-      ((AbstractDraweeController) controller)
-          .addControllerListener(mControllerListener);
-    }
-  }
-
-  @Override
-  protected void onDraw(Canvas canvas) {
-    int saveCount = canvas.save();
-    canvas.concat(mZoomableController.getTransform());
-    super.onDraw(canvas);
-    canvas.restoreToCount(saveCount);
-  }
-
-  @Override
-  public boolean onTouchEvent(MotionEvent event) {
-    if (mZoomableController.onTouchEvent(event)) {
-      if (mZoomableController.getScaleFactor() > 1.0f) {
-        getParent().requestDisallowInterceptTouchEvent(true);
-      }
-      //FLog.v(TAG, "onTouchEvent: view %x, handled by zoomable controller", this.hashCode());
-      return true;
-    }
-    //FLog.v(TAG, "onTouchEvent: view %x, handled by the super", this.hashCode());
-    return super.onTouchEvent(event);
-  }
-
-  @Override
-  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-    FLog.v(TAG, "onLayout: view %x", this.hashCode());
-    super.onLayout(changed, left, top, right, bottom);
-    updateZoomableControllerBounds();
-  }
-
-  private void onFinalImageSet() {
-    FLog.v(TAG, "onFinalImageSet: view %x", this.hashCode());
-    if (!mZoomableController.isEnabled()) {
-      updateZoomableControllerBounds();
-      mZoomableController.setEnabled(true);
-    }
-  }
-
-  private void onRelease() {
-    FLog.v(TAG, "onRelease: view %x", this.hashCode());
-    mZoomableController.setEnabled(false);
-  }
-
-  @Override
-  public void onTransformChanged(Matrix transform) {
-    FLog.v(TAG, "onTransformChanged: view %x", this.hashCode());
-    maybeSetHugeImageController();
-    invalidate();
-  }
-
-  @Override
-  public void onLongClick() {
-    if (mExtraListener != null) {
-      mExtraListener.onLongClick();
-    }
-  }
-
-  @Override
-  public void onSwipeDown() {
-    if (mExtraListener != null) {
-      mExtraListener.onSwipeDown();
-    }
-  }
-
-  private void updateZoomableControllerBounds() {
-    getHierarchy().getActualImageBounds(mImageBounds);
-    mViewBounds.set(0, 0, getWidth(), getHeight());
-    mZoomableController.setImageBounds(mImageBounds);
-    mZoomableController.setViewBounds(mViewBounds);
-    FLog.v(
-            TAG,
-            "updateZoomableControllerBounds: view %x, view bounds: %s, image bounds: %s",
-            this.hashCode(),
-            mViewBounds,
-            mImageBounds);
-  }
+    public void setControllers(
+            @Nullable DraweeController controller,
+            @Nullable DraweeController hugeImageController) {
+        setControllersInternal(null, null);
+        mZoomableController.setEnabled(false);
+        setControllersInternal(controller, hugeImageController);
+    }
+
+    private void maybeSetHugeImageController() {
+        if (mHugeImageController != null &&
+                mZoomableController.getScaleFactor() > HUGE_IMAGE_SCALE_FACTOR_THRESHOLD) {
+            setControllersInternal(mHugeImageController, null);
+        }
+    }
+
+    private void removeControllerListener(DraweeController controller) {
+        if (controller instanceof AbstractDraweeController) {
+            ((AbstractDraweeController) controller)
+                    .removeControllerListener(mControllerListener);
+        }
+    }
+
+    private void addControllerListener(DraweeController controller) {
+        if (controller instanceof AbstractDraweeController) {
+            ((AbstractDraweeController) controller)
+                    .addControllerListener(mControllerListener);
+        }
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        int saveCount = canvas.save();
+        canvas.concat(mZoomableController.getTransform());
+        super.onDraw(canvas);
+        canvas.restoreToCount(saveCount);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (mZoomableController.onTouchEvent(event)) {
+            if (mZoomableController.getScaleFactor() > 1.0f) {
+                getParent().requestDisallowInterceptTouchEvent(true);
+            }
+            //FLog.v(TAG, "onTouchEvent: view %x, handled by zoomable controller", this.hashCode());
+            return true;
+        }
+        //FLog.v(TAG, "onTouchEvent: view %x, handled by the super", this.hashCode());
+        return super.onTouchEvent(event);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        FLog.v(TAG, "onLayout: view %x", this.hashCode());
+        super.onLayout(changed, left, top, right, bottom);
+        updateZoomableControllerBounds();
+    }
+
+    private void onFinalImageSet() {
+        FLog.v(TAG, "onFinalImageSet: view %x", this.hashCode());
+        if (!mZoomableController.isEnabled()) {
+            updateZoomableControllerBounds();
+            mZoomableController.setEnabled(true);
+        }
+    }
+
+    private void onRelease() {
+        FLog.v(TAG, "onRelease: view %x", this.hashCode());
+        mZoomableController.setEnabled(false);
+    }
+
+    @Override
+    public void onTransformChanged(Matrix transform) {
+        FLog.v(TAG, "onTransformChanged: view %x", this.hashCode());
+        maybeSetHugeImageController();
+        invalidate();
+    }
+
+    @Override
+    public void onLongClick() {
+        if (mExtraListener != null) {
+            mExtraListener.onLongClick();
+        }
+    }
+
+    @Override
+    public void onSwipeDown() {
+        if (mExtraListener != null) {
+            mExtraListener.onSwipeDown();
+        }
+    }
+
+    @Override
+    public void onTap() {
+        if (mExtraListener != null) {
+            mExtraListener.onTap();
+        }
+    }
+
+    private void updateZoomableControllerBounds() {
+        getHierarchy().getActualImageBounds(mImageBounds);
+        mViewBounds.set(0, 0, getWidth(), getHeight());
+        mZoomableController.setImageBounds(mImageBounds);
+        mZoomableController.setViewBounds(mViewBounds);
+        FLog.v(
+                TAG,
+                "updateZoomableControllerBounds: view %x, view bounds: %s, image bounds: %s",
+                this.hashCode(),
+                mViewBounds,
+                mImageBounds);
+    }
 
 
 }

+ 1 - 1
frame/log/build.gradle

@@ -7,7 +7,7 @@ plugins {
 ext {
     GROUP_ID = 'com.wenext.android'
     ARTIFACT_ID = 'frame-log'
-    VERSION = '6.0.5'
+    VERSION = '6.0.6'
 }
 
 apply from: "../../publish.gradle"

+ 0 - 2
frame/log/src/main/java/com/adealink/frame/log/manager/ILogService.kt

@@ -16,8 +16,6 @@ interface ILogService {
 
     suspend fun uploadLog(reason: ReportLogReason): Rlt<String>
 
-    suspend fun uploadLongString(fileName: String, str: String): Rlt<String>
-
     fun clearLog(type: ReportLogType)
 
 }

+ 0 - 16
frame/log/src/main/java/com/adealink/frame/log/manager/LogService.kt

@@ -260,22 +260,6 @@ class LogService(val config: ILogConfig) : ILogService,
         }
     }
 
-    override suspend fun uploadLongString(
-        fileName: String,
-        str: String,
-    ): Rlt<String> {
-        return withContext(Dispatcher.WENEXT_THREAD_POOL) {
-            return@withContext config.ossService.suspendUploadFile(
-                UploadFile.ByteFile(
-                    bytes = str.toByteArray(),
-                    fileType = UploadFile.FileType.LONG_STRING,
-                    public = true,
-                    fileName = fileName
-                )
-            )
-        }
-    }
-
     override fun clearLog(type: ReportLogType) {
         when (type) {
             ReportLogType.USER -> {}