From e9bd6881d82b2cca5946fde221cc06dff5d1256c Mon Sep 17 00:00:00 2001 From: Florens Douwes Date: Sun, 3 Aug 2014 11:26:10 +0200 Subject: [PATCH] Some fixes for SubsamplingImageView Fix videos not resetting the progressbar when loaded. --- .../SubsamplingScaleImageView.java | 99 ++++++++++--------- .../chan/ui/view/ThumbnailImageView.java | 2 + 2 files changed, 53 insertions(+), 48 deletions(-) diff --git a/Clover/app/src/main/java/com/davemorrissey/labs/subscaleview/SubsamplingScaleImageView.java b/Clover/app/src/main/java/com/davemorrissey/labs/subscaleview/SubsamplingScaleImageView.java index c722f817..48244857 100644 --- a/Clover/app/src/main/java/com/davemorrissey/labs/subscaleview/SubsamplingScaleImageView.java +++ b/Clover/app/src/main/java/com/davemorrissey/labs/subscaleview/SubsamplingScaleImageView.java @@ -56,11 +56,7 @@ import java.util.Map; * a set of image tiles subsampled at higher resolution are loaded and displayed over the base layer. During pinch and * zoom, tiles off screen or higher/lower resolution than required are discarded from memory. * - * Tiles over 2048px are not used due to hardware rendering limitations. - * - * This view will not work very well with images that are far larger in one dimension than the other because the tile grid - * for each subsampling level has the same number of rows as columns, so each tile has the same width:height ratio as - * the source image. This could result in image data totalling several times the screen area being loaded. + * Tiles are no larger than the max supported bitmap size, so with large images tiling may be used even when zoomed out. * * v prefixes - coordinates, translations and distances measured in screen (view) pixels * s prefixes - coordinates, translations and distances measured in source image pixels (scaled) @@ -194,6 +190,7 @@ public class SubsamplingScaleImageView extends View { super(context, attr); setMinimumDpi(160); setDoubleTapZoomDpi(160); + setGestureDetector(context); this.handler = new Handler(new Handler.Callback() { public boolean handleMessage(Message message) { if (message.what == MESSAGE_LONG_CLICK && onLongClickListener != null) { @@ -205,47 +202,6 @@ public class SubsamplingScaleImageView extends View { return true; } }); - this.detector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { - @Override - public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - if (panEnabled && readySent && vTranslate != null && (Math.abs(e1.getX() - e2.getX()) > 50 || Math.abs(e1.getY() - e2.getY()) > 50) && (Math.abs(velocityX) > 500 || Math.abs(velocityY) > 500) && !isZooming) { - PointF vTranslateEnd = new PointF(vTranslate.x + (velocityX * 0.25f), vTranslate.y + (velocityY * 0.25f)); - float sCenterXEnd = ((getWidth()/2) - vTranslateEnd.x)/scale; - float sCenterYEnd = ((getHeight()/2) - vTranslateEnd.y)/scale; - new AnimationBuilder(new PointF(sCenterXEnd, sCenterYEnd)).withEasing(EASE_OUT_QUAD).withPanLimited(false).start(); - return true; - } - return super.onFling(e1, e2, velocityX, velocityY); - } - - @Override - public boolean onSingleTapConfirmed(MotionEvent e) { - performClick(); - return true; - } - - @Override - public boolean onDoubleTap(MotionEvent e) { - if (zoomEnabled && readySent && vTranslate != null) { - float doubleTapZoomScale = Math.min(maxScale, SubsamplingScaleImageView.this.doubleTapZoomScale); - boolean zoomIn = scale <= doubleTapZoomScale * 0.9; - float targetScale = zoomIn ? doubleTapZoomScale : Math.min(getWidth() / (float) sWidth(), getHeight() / (float) sHeight()); - PointF targetSCenter = viewToSourceCoord(new PointF(e.getX(), e.getY())); - if (doubleTapZoomStyle == ZOOM_FOCUS_CENTER_IMMEDIATE) { - setScaleAndCenter(targetScale, targetSCenter); - } else if (doubleTapZoomStyle == ZOOM_FOCUS_CENTER || !zoomIn) { - new AnimationBuilder(targetScale, targetSCenter).withInterruptible(false).start(); - } else if (doubleTapZoomStyle == ZOOM_FOCUS_FIXED) { - new AnimationBuilder(targetScale, targetSCenter, new PointF(e.getX(), e.getY())).withInterruptible(false).start(); - } - - invalidate(); - return true; - } - return super.onDoubleTapEvent(e); - } - }); - // Handle XML attributes /*if (attr != null) { TypedArray typedAttr = getContext().obtainStyledAttributes(attr, styleable.SubsamplingScaleImageView); @@ -375,6 +331,53 @@ public class SubsamplingScaleImageView extends View { } } + private void setGestureDetector(final Context context) { + this.detector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + if (panEnabled && readySent && vTranslate != null && e1 != null && e2 != null && (Math.abs(e1.getX() - e2.getX()) > 50 || Math.abs(e1.getY() - e2.getY()) > 50) && (Math.abs(velocityX) > 500 || Math.abs(velocityY) > 500) && !isZooming) { + PointF vTranslateEnd = new PointF(vTranslate.x + (velocityX * 0.25f), vTranslate.y + (velocityY * 0.25f)); + float sCenterXEnd = ((getWidth()/2) - vTranslateEnd.x)/scale; + float sCenterYEnd = ((getHeight()/2) - vTranslateEnd.y)/scale; + new AnimationBuilder(new PointF(sCenterXEnd, sCenterYEnd)).withEasing(EASE_OUT_QUAD).withPanLimited(false).start(); + return true; + } + return super.onFling(e1, e2, velocityX, velocityY); + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + performClick(); + return true; + } + + @Override + public boolean onDoubleTap(MotionEvent e) { + if (zoomEnabled && readySent && vTranslate != null) { + float doubleTapZoomScale = Math.min(maxScale, SubsamplingScaleImageView.this.doubleTapZoomScale); + boolean zoomIn = scale <= doubleTapZoomScale * 0.9; + float targetScale = zoomIn ? doubleTapZoomScale : Math.min(getWidth() / (float) sWidth(), getHeight() / (float) sHeight()); + PointF targetSCenter = viewToSourceCoord(new PointF(e.getX(), e.getY())); + if (doubleTapZoomStyle == ZOOM_FOCUS_CENTER_IMMEDIATE) { + setScaleAndCenter(targetScale, targetSCenter); + } else if (doubleTapZoomStyle == ZOOM_FOCUS_CENTER || !zoomIn) { + new AnimationBuilder(targetScale, targetSCenter).withInterruptible(false).start(); + } else if (doubleTapZoomStyle == ZOOM_FOCUS_FIXED) { + new AnimationBuilder(targetScale, targetSCenter, new PointF(e.getX(), e.getY())).withInterruptible(false).start(); + } + + // Hacky solution for #15 - after a double tap the GestureDetector gets in a state where the next + // fling is ignored, so here we replace it with a new one. + setGestureDetector(context); + + invalidate(); + return true; + } + return super.onDoubleTapEvent(e); + } + }); + } + /** * On resize, preserve center and scale. Various behaviours are possible, override this method to use another. */ @@ -1773,8 +1776,8 @@ public class SubsamplingScaleImageView extends View { anim.sCenterEnd = targetSCenter; anim.vFocusStart = sourceToViewCoord(targetSCenter); anim.vFocusEnd = new PointF( - getWidth()/2, - getHeight()/2 + getWidth()/2, + getHeight()/2 ); anim.duration = duration; anim.interruptible = interruptible; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/ThumbnailImageView.java b/Clover/app/src/main/java/org/floens/chan/ui/view/ThumbnailImageView.java index b095785f..8f36d5cc 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/ThumbnailImageView.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/view/ThumbnailImageView.java @@ -277,10 +277,12 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener callback.onVideoLoaded(); } }); + videoView.setVideoPath(file.getAbsolutePath()); setView(videoView, false); callback.setProgress(false); + callback.setLinearProgress(0, 0, true); thumbnailNeeded = false; videoView.start();