From 463b7e52917dd6d4414ddb64b82568d61475e925 Mon Sep 17 00:00:00 2001 From: Floens Date: Sat, 28 Mar 2015 17:55:04 +0100 Subject: [PATCH] Use a new method of transition view that does not need measures. --- .../core/presenter/ImageViewerPresenter.java | 11 +- .../chan/core/presenter/ThreadPresenter.java | 14 ++ .../ui/controller/ImageViewerController.java | 195 ++++++++---------- .../chan/ui/controller/ThreadController.java | 20 +- .../floens/chan/ui/layout/ThreadLayout.java | 9 + .../chan/ui/layout/ThreadListLayout.java | 24 +++ .../chan/ui/view/ClippingImageView.java | 41 ---- .../org/floens/chan/ui/view/PostView.java | 8 + .../chan/ui/view/TransitionImageView.java | 117 +++++++++++ .../org/floens/chan/utils/AnimationUtils.java | 64 ------ .../res/layout/controller_image_viewer.xml | 2 +- 11 files changed, 272 insertions(+), 233 deletions(-) delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/view/ClippingImageView.java create mode 100644 Clover/app/src/main/java/org/floens/chan/ui/view/TransitionImageView.java diff --git a/Clover/app/src/main/java/org/floens/chan/core/presenter/ImageViewerPresenter.java b/Clover/app/src/main/java/org/floens/chan/core/presenter/ImageViewerPresenter.java index 39a2166f..dc7e6e58 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/presenter/ImageViewerPresenter.java +++ b/Clover/app/src/main/java/org/floens/chan/core/presenter/ImageViewerPresenter.java @@ -45,7 +45,7 @@ public class ImageViewerPresenter implements MultiImageView.Callback, ViewPager. public void onViewMeasured() { // Pager is measured, but still invisible - callback.startPreviewInTransition(); + callback.startPreviewInTransition(images.get(selectedPosition)); callback.setTitle(images.get(selectedPosition)); } @@ -64,7 +64,7 @@ public class ImageViewerPresenter implements MultiImageView.Callback, ViewPager. callback.setPagerVisiblity(false); callback.setPreviewVisibility(true); - callback.startPreviewOutTransition(); + callback.startPreviewOutTransition(images.get(selectedPosition)); } @Override @@ -119,6 +119,7 @@ public class ImageViewerPresenter implements MultiImageView.Callback, ViewPager. private void onPageSwipedTo(int position) { callback.setTitle(images.get(selectedPosition)); + callback.scrollTo(images.get(selectedPosition)); for (PostImage other : getOther(position, false)) { callback.setImageMode(other, MultiImageView.Mode.LOWRES); @@ -186,9 +187,9 @@ public class ImageViewerPresenter implements MultiImageView.Callback, ViewPager. } public interface Callback { - public void startPreviewInTransition(); + public void startPreviewInTransition(PostImage postImage); - public void startPreviewOutTransition(); + public void startPreviewOutTransition(PostImage postImage); public void setPreviewVisibility(boolean visible); @@ -200,6 +201,8 @@ public class ImageViewerPresenter implements MultiImageView.Callback, ViewPager. public void setTitle(PostImage postImage); + public void scrollTo(PostImage postImage); + public MultiImageView.Mode getImageMode(PostImage postImage); } } diff --git a/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java b/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java index bc0e00e4..8e75cdef 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java +++ b/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java @@ -119,7 +119,19 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt @Override public void scrollTo(int position) { + threadPresenterCallback.scrollTo(position); + } + public void scrollTo(PostImage postImage) { + int position = -1; + for (int i = 0; i < chanLoader.getThread().posts.size(); i++) { + Post post = chanLoader.getThread().posts.get(i); + if (post.hasImage && post.imageUrl.equals(postImage.imageUrl)) { + position = i; + break; + } + } + scrollTo(position); } /* @@ -328,5 +340,7 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt public void showPostsPopup(Post forPost, List posts); public void showImages(List images, int index, ImageView thumbnail); + + public void scrollTo(int position); } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java index 354c8814..7ecc0608 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java @@ -7,35 +7,39 @@ import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.app.Activity; import android.content.Context; +import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Point; -import android.graphics.Rect; +import android.graphics.drawable.BitmapDrawable; import android.os.Build; +import android.util.Log; import android.view.View; import android.view.Window; import android.view.animation.DecelerateInterpolator; import android.widget.ImageView; +import com.android.volley.VolleyError; +import com.android.volley.toolbox.ImageLoader; + +import org.floens.chan.ChanApplication; import org.floens.chan.R; import org.floens.chan.controller.Controller; import org.floens.chan.core.model.PostImage; import org.floens.chan.core.presenter.ImageViewerPresenter; import org.floens.chan.ui.adapter.ImageViewerAdapter; import org.floens.chan.ui.toolbar.Toolbar; -import org.floens.chan.ui.view.ClippingImageView; -import org.floens.chan.ui.view.OptionalSwipeViewPager; import org.floens.chan.ui.view.MultiImageView; +import org.floens.chan.ui.view.OptionalSwipeViewPager; +import org.floens.chan.ui.view.TransitionImageView; import org.floens.chan.utils.AndroidUtils; -import org.floens.chan.utils.AnimationUtils; import java.util.List; import static org.floens.chan.utils.AndroidUtils.dp; -import static org.floens.chan.utils.AnimationUtils.calculateBoundsAnimation; public class ImageViewerController extends Controller implements View.OnClickListener, ImageViewerPresenter.Callback { - private static final int TRANSITION_DURATION = 200; //165; - private static final int TRANSITION_CLIP_DURATION = (int) (TRANSITION_DURATION * 0.5f); + private static final String TAG = "ImageViewerController"; + private static final int TRANSITION_DURATION = 200; private static final float TRANSITION_FINAL_ALPHA = 0.80f; private int statusBarColorPrevious; @@ -46,7 +50,7 @@ public class ImageViewerController extends Controller implements View.OnClickLis private ImageViewerPresenter presenter; private final Toolbar toolbar; - private ClippingImageView previewImage; + private TransitionImageView previewImage; private OptionalSwipeViewPager pager; public ImageViewerController(Context context, Toolbar toolbar) { @@ -62,7 +66,7 @@ public class ImageViewerController extends Controller implements View.OnClickLis view = inflateRes(R.layout.controller_image_viewer); view.setOnClickListener(this); - previewImage = (ClippingImageView) view.findViewById(R.id.preview_image); + previewImage = (TransitionImageView) view.findViewById(R.id.preview_image); pager = (OptionalSwipeViewPager) view.findViewById(R.id.pager); pager.setOnPageChangeListener(presenter); @@ -95,7 +99,7 @@ public class ImageViewerController extends Controller implements View.OnClickLis } public void setPreviewVisibility(boolean visible) { - previewImage.setVisibility(visible ? View.VISIBLE : View.GONE); + previewImage.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); } public void setPagerVisiblity(boolean visible) { @@ -122,69 +126,34 @@ public class ImageViewerController extends Controller implements View.OnClickLis toolbar.setNavigationItem(false, false, navigationItem); } - public void startPreviewInTransition() { - ImageView previewImageView = previewCallback.getPreviewImageStartView(this); - previewImage.setImageDrawable(previewImageView.getDrawable()); - - Rect startBounds = getImageViewBounds(previewImageView); - final Rect endBounds = new Rect(); - final Point globalOffset = new Point(); - view.getGlobalVisibleRect(endBounds, globalOffset); - float startScale = calculateBoundsAnimation(startBounds, endBounds, globalOffset); + public void scrollTo(PostImage postImage) { + previewCallback.scrollTo(postImage); + } - previewImage.setPivotX(0f); - previewImage.setPivotY(0f); - previewImage.setX(startBounds.left); - previewImage.setY(startBounds.top); - previewImage.setScaleX(startScale); - previewImage.setScaleY(startScale); + public void startPreviewInTransition(PostImage postImage) { + ImageView startImageView = getTransitionImageView(postImage); - Rect clipStartBounds = new Rect(0, 0, (int) (previewImageView.getWidth() / startScale), (int) (previewImageView.getHeight() / startScale)); + if (!setTransitionViewData(startImageView)) { + return; // TODO + } if (Build.VERSION.SDK_INT >= 21) { statusBarColorPrevious = getWindow().getStatusBarColor(); } - doPreviewInTransition(startBounds, endBounds, startScale, clipStartBounds); - } - - public void startPreviewOutTransition() { - if (startPreviewAnimation != null || endAnimation != null) { - return; - } - - doPreviewOutAnimation(); - } - - private void doPreviewInTransition(Rect startBounds, Rect finalBounds, float startScale, final Rect clipStartBounds) { startPreviewAnimation = new AnimatorSet(); - ValueAnimator backgroundAlpha = ValueAnimator.ofFloat(0f, 1f); - backgroundAlpha.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + ValueAnimator progress = ValueAnimator.ofFloat(0f, 1f); + progress.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { setBackgroundAlpha((float) animation.getAnimatedValue()); + previewImage.setProgress((float) animation.getAnimatedValue()); } }); - final Rect clipRect = new Rect(); - ValueAnimator clip = ValueAnimator.ofFloat(1f, 0f); - clip.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - AnimationUtils.getClippingBounds(clipStartBounds, previewImage, clipRect, (float) animation.getAnimatedValue()); - previewImage.clip(clipRect); - } - }); - - startPreviewAnimation - .play(ObjectAnimator.ofFloat(previewImage, View.X, startBounds.left, finalBounds.left).setDuration(TRANSITION_DURATION)) - .with(ObjectAnimator.ofFloat(previewImage, View.Y, startBounds.top, finalBounds.top).setDuration(TRANSITION_DURATION)) - .with(ObjectAnimator.ofFloat(previewImage, View.SCALE_X, startScale, 1f).setDuration(TRANSITION_DURATION)) - .with(ObjectAnimator.ofFloat(previewImage, View.SCALE_Y, startScale, 1f).setDuration(TRANSITION_DURATION)) - .with(backgroundAlpha.setDuration(TRANSITION_DURATION)) - .with(clip.setDuration(TRANSITION_CLIP_DURATION)); - + startPreviewAnimation.play(progress); + startPreviewAnimation.setDuration(TRANSITION_DURATION); startPreviewAnimation.setInterpolator(new DecelerateInterpolator()); startPreviewAnimation.addListener(new AnimatorListenerAdapter() { @Override @@ -194,11 +163,6 @@ public class ImageViewerController extends Controller implements View.OnClickLis @Override public void onAnimationEnd(Animator animation) { - previewImage.setX(0f); - previewImage.setY(0f); - previewImage.setScaleX(1f); - previewImage.setScaleY(1f); - previewImage.clip(null); startPreviewAnimation = null; presenter.onInTransitionEnd(); } @@ -206,13 +170,30 @@ public class ImageViewerController extends Controller implements View.OnClickLis startPreviewAnimation.start(); } - private void doPreviewOutAnimation() { - ImageView startImage = getStartImageView(); - Rect startBounds = null; - if (startImage != null) { - startBounds = getImageViewBounds(startImage); + public void startPreviewOutTransition(final PostImage postImage) { + if (startPreviewAnimation != null || endAnimation != null) { + return; } - if (startBounds == null) { + + // Should definitely be loaded + ChanApplication.getVolleyImageLoader().get(postImage.thumbnailUrl, new ImageLoader.ImageListener() { + @Override + public void onErrorResponse(VolleyError error) { + Log.e(TAG, "onErrorResponse for preview out transition in ImageViewerController, cannot show correct transition bitmap"); + doPreviewOutAnimation(postImage, null); + } + + @Override + public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) { + doPreviewOutAnimation(postImage, response.getBitmap()); + } + }, previewImage.getWidth(), previewImage.getHeight()); + } + + private void doPreviewOutAnimation(PostImage postImage, Bitmap bitmap) { + ImageView startImage = getTransitionImageView(postImage); + + if (!setTransitionViewData(startImage) || bitmap == null) { endAnimation = new AnimatorSet(); ValueAnimator backgroundAlpha = ValueAnimator.ofFloat(1f, 0f); @@ -238,44 +219,26 @@ public class ImageViewerController extends Controller implements View.OnClickLis }); endAnimation.start(); } else { - final Rect endBounds = new Rect(); - final Point globalOffset = new Point(); - view.getGlobalVisibleRect(endBounds, globalOffset); - float startScale = calculateBoundsAnimation(startBounds, endBounds, globalOffset); - endAnimation = new AnimatorSet(); - ValueAnimator backgroundAlpha = ValueAnimator.ofFloat(1f, 0f); - backgroundAlpha.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + ValueAnimator progress = ValueAnimator.ofFloat(1f, 0f); + progress.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { setBackgroundAlpha((float) animation.getAnimatedValue()); + previewImage.setProgress((float) animation.getAnimatedValue()); } }); - final Rect clipStartBounds = new Rect(0, 0, (int) (startImage.getWidth() / startScale), (int) (startImage.getHeight() / startScale)); - final Rect clipRect = new Rect(); - ValueAnimator clip = ValueAnimator.ofFloat(0f, 1f); - clip.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + endAnimation.play(progress); + endAnimation.setDuration(TRANSITION_DURATION); + endAnimation.setInterpolator(new DecelerateInterpolator()); + endAnimation.addListener(new AnimatorListenerAdapter() { @Override - public void onAnimationUpdate(ValueAnimator animation) { - AnimationUtils.getClippingBounds(clipStartBounds, previewImage, clipRect, (float) animation.getAnimatedValue()); - previewImage.clip(clipRect); + public void onAnimationStart(Animator animation) { + previewCallback.onPreviewCreate(ImageViewerController.this); } - }); - clip.setStartDelay(TRANSITION_DURATION - TRANSITION_CLIP_DURATION); - clip.setDuration(TRANSITION_CLIP_DURATION); - endAnimation - .play(ObjectAnimator.ofFloat(previewImage, View.X, startBounds.left).setDuration(TRANSITION_DURATION)) - .with(ObjectAnimator.ofFloat(previewImage, View.Y, startBounds.top).setDuration(TRANSITION_DURATION)) - .with(ObjectAnimator.ofFloat(previewImage, View.SCALE_X, 1f, startScale).setDuration(TRANSITION_DURATION)) - .with(ObjectAnimator.ofFloat(previewImage, View.SCALE_Y, 1f, startScale).setDuration(TRANSITION_DURATION)) - .with(backgroundAlpha.setDuration(TRANSITION_DURATION)) - .with(clip); - - endAnimation.setInterpolator(new DecelerateInterpolator()); - endAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { previewOutAnimationEnded(); @@ -292,6 +255,24 @@ public class ImageViewerController extends Controller implements View.OnClickLis navigationController.stopPresenting(false); } + private boolean setTransitionViewData(ImageView startView) { + if (startView == null || startView.getWindowToken() == null) { + return false; + } + + Bitmap bitmap = ((BitmapDrawable) startView.getDrawable()).getBitmap(); + if (bitmap == null) { + return false; + } + + int[] loc = new int[2]; + startView.getLocationInWindow(loc); + Point windowLocation = new Point(loc[0], loc[1]); + Point size = new Point(startView.getWidth(), startView.getHeight()); + previewImage.setSourceImageView(windowLocation, size, bitmap); + return true; + } + private void setBackgroundAlpha(float alpha) { view.setBackgroundColor(Color.argb((int) (alpha * TRANSITION_FINAL_ALPHA * 255f), 0, 0, 0)); @@ -319,22 +300,8 @@ public class ImageViewerController extends Controller implements View.OnClickLis toolbar.setAlpha(alpha); } - private Rect getImageViewBounds(ImageView image) { - Rect startBounds = new Rect(); - if (image.getGlobalVisibleRect(startBounds) && !startBounds.isEmpty()) { - AnimationUtils.adjustImageViewBoundsToDrawableBounds(image, startBounds); - if (!startBounds.isEmpty()) { - return startBounds; - } else { - return null; - } - } else { - return null; - } - } - - private ImageView getStartImageView() { - return previewCallback.getPreviewImageStartView(this); + private ImageView getTransitionImageView(PostImage postImage) { + return previewCallback.getPreviewImageTransitionView(this, postImage); } private Window getWindow() { @@ -342,10 +309,12 @@ public class ImageViewerController extends Controller implements View.OnClickLis } public interface PreviewCallback { - public ImageView getPreviewImageStartView(ImageViewerController imageViewerController); + public ImageView getPreviewImageTransitionView(ImageViewerController imageViewerController, PostImage postImage); public void onPreviewCreate(ImageViewerController imageViewerController); public void onPreviewDestroy(ImageViewerController imageViewerController); + + public void scrollTo(PostImage postImage); } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java index 07cf7b0d..99e89774 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java @@ -1,7 +1,6 @@ package org.floens.chan.ui.controller; import android.content.Context; -import android.view.View; import android.widget.ImageView; import org.floens.chan.controller.Controller; @@ -12,7 +11,6 @@ import java.util.List; public abstract class ThreadController extends Controller implements ThreadLayout.ThreadLayoutCallback, ImageViewerController.PreviewCallback { protected ThreadLayout threadLayout; - private ImageView presentingImageView; public ThreadController(Context context) { super(context); @@ -25,9 +23,7 @@ public abstract class ThreadController extends Controller implements ThreadLayou @Override public void showImages(List images, int index, final ImageView thumbnail) { // Just ignore the showImages request when the image is not loaded - if (thumbnail.getDrawable() != null) { - presentingImageView = thumbnail; - + if (thumbnail.getDrawable() != null && thumbnail.getDrawable().getIntrinsicWidth() > 0 && thumbnail.getDrawable().getIntrinsicHeight() > 0) { final ImageViewerNavigationController imageViewerNavigationController = new ImageViewerNavigationController(context); presentController(imageViewerNavigationController, false); imageViewerNavigationController.showImages(images, index, this); @@ -35,17 +31,21 @@ public abstract class ThreadController extends Controller implements ThreadLayou } @Override - public ImageView getPreviewImageStartView(ImageViewerController imageViewerController) { - return presentingImageView; + public ImageView getPreviewImageTransitionView(ImageViewerController imageViewerController, PostImage postImage) { + return threadLayout.getThumbnail(postImage); } public void onPreviewCreate(ImageViewerController imageViewerController) { - presentingImageView.setVisibility(View.INVISIBLE); +// presentingImageView.setVisibility(View.INVISIBLE); } @Override public void onPreviewDestroy(ImageViewerController imageViewerController) { - presentingImageView.setVisibility(View.VISIBLE); - presentingImageView = null; +// presentingImageView.setVisibility(View.VISIBLE); +// presentingImageView = null; + } + + public void scrollTo(PostImage postImage) { + threadLayout.getPresenter().scrollTo(postImage); } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java b/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java index 24121f2a..6c09812f 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java @@ -168,6 +168,15 @@ public class ThreadLayout extends LoadView implements ThreadPresenter.ThreadPres callback.showImages(images, index, thumbnail); } + @Override + public void scrollTo(int position) { + threadListLayout.scrollTo(position); + } + + public ImageView getThumbnail(PostImage postImage) { + return threadListLayout.getThumbnail(postImage); + } + private void switchVisible(boolean visible) { if (this.visible != visible) { this.visible = visible; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadListLayout.java b/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadListLayout.java index 10e71e82..17d7e521 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadListLayout.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadListLayout.java @@ -19,12 +19,16 @@ package org.floens.chan.ui.layout; import android.content.Context; import android.util.AttributeSet; +import android.view.View; +import android.widget.ImageView; import android.widget.ListView; import android.widget.RelativeLayout; import com.android.volley.VolleyError; import org.floens.chan.core.model.ChanThread; +import org.floens.chan.core.model.Post; +import org.floens.chan.core.model.PostImage; import org.floens.chan.ui.adapter.PostAdapter; import org.floens.chan.ui.view.PostView; @@ -93,4 +97,24 @@ public class ThreadListLayout extends RelativeLayout { public void showError(VolleyError error) { } + + public ImageView getThumbnail(PostImage postImage) { + ImageView thumbnail = null; + for (int i = 0; i < listView.getChildCount(); i++) { + View view = listView.getChildAt(i); + if (view instanceof PostView) { + PostView postView = (PostView) view; + Post post = postView.getPost(); + if (post.hasImage && post.imageUrl.equals(postImage.imageUrl)) { + thumbnail = postView.getThumbnail(); + break; + } + } + } + return thumbnail; + } + + public void scrollTo(int position) { + listView.smoothScrollToPosition(position); + } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/ClippingImageView.java b/Clover/app/src/main/java/org/floens/chan/ui/view/ClippingImageView.java deleted file mode 100644 index 0987d737..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/ClippingImageView.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.floens.chan.ui.view; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.widget.ImageView; - -public class ClippingImageView extends ImageView { - private Rect clipRect = new Rect(); - - public ClippingImageView(Context context) { - super(context); - } - - public ClippingImageView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public ClippingImageView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - @Override - protected void onDraw(Canvas canvas) { - if (!clipRect.isEmpty() && (clipRect.width() < getWidth() || clipRect.height() < getHeight())) { - canvas.clipRect(clipRect); - } - - super.onDraw(canvas); - } - - public void clip(Rect rect) { - if (rect == null) { - clipRect.setEmpty(); - } else { - clipRect.set(rect); - } - invalidate(); - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/PostView.java b/Clover/app/src/main/java/org/floens/chan/ui/view/PostView.java index 5d7df31a..4429b03d 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/PostView.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/view/PostView.java @@ -254,6 +254,14 @@ public class PostView extends LinearLayout implements View.OnClickListener { } } + public Post getPost() { + return post; + } + + public ImageView getThumbnail() { + return imageView; + } + public void setHighlightQuotesWithNo(int no) { highlightQuotesNo = no; } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/TransitionImageView.java b/Clover/app/src/main/java/org/floens/chan/ui/view/TransitionImageView.java new file mode 100644 index 00000000..4df57024 --- /dev/null +++ b/Clover/app/src/main/java/org/floens/chan/ui/view/TransitionImageView.java @@ -0,0 +1,117 @@ +package org.floens.chan.ui.view; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Point; +import android.graphics.PointF; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.View; + +public class TransitionImageView extends View { + private static final String TAG = "TransitionImageView"; + + private Bitmap bitmap; + private Matrix matrix = new Matrix(); + private Paint paint = new Paint(); + private RectF bitmapRect = new RectF(); + private RectF destRect = new RectF(); + private RectF sourceImageRect = new RectF(); + private PointF sourceOverlap = new PointF(); + private RectF destClip = new RectF(); + private float progress; + + public TransitionImageView(Context context) { + super(context); + init(); + } + + public TransitionImageView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public TransitionImageView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + public void setSourceImageView(Point windowLocation, Point viewSize, Bitmap bitmap) { + this.bitmap = bitmap; + bitmapRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight()); + + int[] myLoc = new int[2]; + getLocationInWindow(myLoc); + float globalOffsetX = windowLocation.x - myLoc[0]; + float globalOffsetY = windowLocation.y - myLoc[1]; + + // Get the coords in the image view with the center crop method + float scaleX = (float) viewSize.x / (float) bitmap.getWidth(); + float scaleY = (float) viewSize.y / (float) bitmap.getHeight(); + float scale = scaleX > scaleY ? scaleX : scaleY; + float scaledX = bitmap.getWidth() * scale; + float scaledY = bitmap.getHeight() * scale; + float offsetX = (scaledX - viewSize.x) * 0.5f; + float offsetY = (scaledY - viewSize.y) * 0.5f; + + sourceOverlap.set(offsetX, offsetY); + + sourceImageRect.set( + -offsetX + globalOffsetX, + -offsetY + globalOffsetY, + scaledX - offsetX + globalOffsetX, + scaledY - offsetY + globalOffsetY); + } + + public void setProgress(float progress) { + this.progress = progress; + + // Center inside method + float destScale = Math.min( + (float) getWidth() / (float) bitmap.getWidth(), + (float) getHeight() / (float) bitmap.getHeight()); + float destOffsetX = (getWidth() - bitmap.getWidth() * destScale) * 0.5f; + float destOffsetY = (getHeight() - bitmap.getHeight() * destScale) * 0.5f; + float destRight = bitmap.getWidth() * destScale + destOffsetX; + float destBottom = bitmap.getHeight() * destScale + destOffsetY; + + float left = sourceImageRect.left + (destOffsetX - sourceImageRect.left) * progress; + float top = sourceImageRect.top + (destOffsetY - sourceImageRect.top) * progress; + float right = sourceImageRect.right + (destRight - sourceImageRect.right) * progress; + float bottom = sourceImageRect.bottom + (destBottom - sourceImageRect.bottom) * progress; + + destRect.set(left, top, right, bottom); + + destClip.set( + left + sourceOverlap.x * (1f - progress), + top + sourceOverlap.y * (1f - progress), + right - sourceOverlap.x * (1f - progress), + bottom - sourceOverlap.y * (1f - progress) + ); + + invalidate(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (bitmap != null) { + matrix.setRectToRect(bitmapRect, destRect, Matrix.ScaleToFit.FILL); + canvas.save(); + if (progress < 1f) { + canvas.clipRect(destClip); + } + canvas.drawBitmap(bitmap, matrix, paint); + canvas.restore(); + } + } + + private void init() { + paint.setAntiAlias(true); + paint.setFilterBitmap(true); + } +} diff --git a/Clover/app/src/main/java/org/floens/chan/utils/AnimationUtils.java b/Clover/app/src/main/java/org/floens/chan/utils/AnimationUtils.java index 45de5745..231cab8c 100644 --- a/Clover/app/src/main/java/org/floens/chan/utils/AnimationUtils.java +++ b/Clover/app/src/main/java/org/floens/chan/utils/AnimationUtils.java @@ -17,76 +17,12 @@ */ package org.floens.chan.utils; -import android.graphics.Matrix; -import android.graphics.Point; -import android.graphics.Rect; import android.view.View; import android.view.animation.Animation; -import android.widget.ImageView; import org.floens.chan.ui.animation.HeightAnimation; public class AnimationUtils { - /** - * On your start view call startView.getGlobalVisibleRect(startBounds) - * and on your end container call endContainer.getGlobalVisibleRect(endBounds, globalOffset);
- * startBounds and endBounds will be adjusted appropriately and the starting scale will be returned. - * - * @param startBounds your startBounds - * @param endBounds your endBounds - * @param globalOffset your globalOffset - * @return the starting scale - */ - public static float calculateBoundsAnimation(Rect startBounds, Rect endBounds, Point globalOffset) { - startBounds.offset(-globalOffset.x, -globalOffset.y); - endBounds.offset(-globalOffset.x, -globalOffset.y); - - float startScale; - if ((float) endBounds.width() / endBounds.height() > (float) startBounds.width() / startBounds.height()) { - // Extend start bounds horizontally - startScale = (float) startBounds.height() / endBounds.height(); - float startWidth = startScale * endBounds.width(); - float deltaWidth = (startWidth - startBounds.width()) / 2; - startBounds.left -= deltaWidth; - startBounds.right += deltaWidth; - } else { - // Extend start bounds vertically - startScale = (float) startBounds.width() / endBounds.width(); - float startHeight = startScale * endBounds.height(); - float deltaHeight = (startHeight - startBounds.height()) / 2; - startBounds.top -= deltaHeight; - startBounds.bottom += deltaHeight; - } - - return startScale; - } - - public static void getClippingBounds(Rect clipStartBounds, ImageView view, Rect out, float progress) { - float[] f = new float[9]; - view.getImageMatrix().getValues(f); - float imageWidth = view.getDrawable().getIntrinsicWidth() * f[Matrix.MSCALE_X]; - float imageHeight = view.getDrawable().getIntrinsicHeight() * f[Matrix.MSCALE_Y]; - float imageWidthDiff = (view.getWidth() - imageWidth) / 2f; - float imageHeightDiff = (view.getHeight() - imageHeight) / 2f; - - float offsetWidth = ((imageWidth - clipStartBounds.right) / 2f) * progress; - float offsetHeight = ((imageHeight - clipStartBounds.bottom) / 2f) * progress; - - out.set((int) (offsetWidth + imageWidthDiff), - (int) (offsetHeight + imageHeightDiff), - (int) (view.getWidth() - offsetWidth - imageWidthDiff), - (int) (view.getHeight() - offsetHeight - imageHeightDiff)); - } - - public static void adjustImageViewBoundsToDrawableBounds(ImageView imageView, Rect bounds) { - float[] f = new float[9]; - imageView.getImageMatrix().getValues(f); - bounds.left += f[Matrix.MTRANS_X]; - bounds.top += f[Matrix.MTRANS_Y]; - bounds.right = (bounds.left + (int) (imageView.getDrawable().getIntrinsicWidth() * f[Matrix.MSCALE_X])); - bounds.bottom = (bounds.top + (int) (imageView.getDrawable().getIntrinsicHeight() * f[Matrix.MSCALE_Y])); - } - public static void setHeight(View view, boolean expand, boolean animated) { setHeight(view, expand, animated, -1); } diff --git a/Clover/app/src/main/res/layout/controller_image_viewer.xml b/Clover/app/src/main/res/layout/controller_image_viewer.xml index a145038f..27cf88bf 100644 --- a/Clover/app/src/main/res/layout/controller_image_viewer.xml +++ b/Clover/app/src/main/res/layout/controller_image_viewer.xml @@ -3,7 +3,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> -