package com.jasonchen.microlang.gallery; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.Rect; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.animation.AccelerateDecelerateInterpolator; import com.jasonchen.microlang.R; import com.jasonchen.microlang.utils.AnimationRect; import com.jasonchen.microlang.utils.AnimationUtility; import com.jasonchen.microlang.utils.SettingUtility; import com.jasonchen.microlang.utils.Utility; import com.jasonchen.microlang.utils.image.ImageUtility; import com.jasonchen.microlang.view.ClipImageView; import java.io.File; import java.io.IOException; import photoview.PhotoView; import photoview.PhotoViewAttacher; import pl.droidsonroids.gif.GifDrawable; /** * jasonchen * 2015/04/10 */ public class GifPictureFragment extends Fragment { private static final int NAVIGATION_BAR_HEIGHT_DP_UNIT = 48; private static final int ANIMATION_DURATION = 300; private static final int IMAGEVIEW_SOFT_LAYER_MAX_WIDTH = 2000; private static final int IMAGEVIEW_SOFT_LAYER_MAX_HEIGHT = 3000; private PhotoView gifImageView; public static GifPictureFragment newInstance(String path, AnimationRect rect, boolean animationIn) { GifPictureFragment fragment = new GifPictureFragment(); Bundle bundle = new Bundle(); bundle.putString("path", path); bundle.putParcelable("rect", rect); bundle.putBoolean("animationIn", animationIn); fragment.setArguments(bundle); return fragment; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.gallery_gif_layout, container, false); gifImageView = (PhotoView) view.findViewById(R.id.gif); if (SettingUtility.allowClickToCloseGallery()) { gifImageView.setOnViewTapListener(new PhotoViewAttacher.OnViewTapListener() { @Override public void onViewTap(View view, float x, float y) { getActivity().onBackPressed(); } }); } LongClickListener longClickListener = ((ContainerFragment) getParentFragment()) .getLongClickListener(); gifImageView.setOnLongClickListener(longClickListener); String path = getArguments().getString("path"); boolean animateIn = getArguments().getBoolean("animationIn"); final AnimationRect rect = getArguments().getParcelable("rect"); File gifFile = new File(path); try { GifDrawable gifFromFile = new GifDrawable(gifFile); gifImageView.setImageDrawable(gifFromFile); } catch (IOException e) { e.printStackTrace(); } final ClipImageView photoView = (ClipImageView) view.findViewById(R.id.cover); Bitmap bitmap = ImageUtility .decodeBitmapFromSDCard(path, IMAGEVIEW_SOFT_LAYER_MAX_WIDTH, IMAGEVIEW_SOFT_LAYER_MAX_HEIGHT); photoView.setImageBitmap(bitmap); if (!animateIn) { photoView.setVisibility(View.INVISIBLE); return view; } gifImageView.setVisibility(View.INVISIBLE); final Runnable endAction = new Runnable() { @Override public void run() { Bundle bundle = getArguments(); bundle.putBoolean("animationIn", false); photoView.setVisibility(View.INVISIBLE); gifImageView.setVisibility(View.VISIBLE); } }; photoView.getViewTreeObserver() .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @SuppressLint("NewApi") @Override public boolean onPreDraw() { if (rect == null) { photoView.getViewTreeObserver().removeOnPreDrawListener(this); endAction.run(); return true; } final Rect startBounds = new Rect(rect.scaledBitmapRect); final Rect finalBounds = AnimationUtility .getBitmapRectFromImageView(photoView); if (finalBounds == null) { photoView.getViewTreeObserver().removeOnPreDrawListener(this); endAction.run(); return true; } float startScale = (float) finalBounds.width() / startBounds.width(); if (startScale * startBounds.height() > finalBounds.height()) { startScale = (float) finalBounds.height() / startBounds.height(); } int oriBitmapScaledWidth = (int) (finalBounds.width() / startScale); int oriBitmapScaledHeight = (int) (finalBounds.height() / startScale); int thumbnailAndOriDeltaRightSize = Math .abs(rect.scaledBitmapRect.width() - oriBitmapScaledWidth); int thumbnailAndOriDeltaBottomSize = Math .abs(rect.scaledBitmapRect.height() - oriBitmapScaledHeight); float thumbnailAndOriDeltaWidth = (float) thumbnailAndOriDeltaRightSize / (float) oriBitmapScaledWidth; float thumbnailAndOriDeltaHeight = (float) thumbnailAndOriDeltaBottomSize / (float) oriBitmapScaledHeight; int deltaTop = startBounds.top - finalBounds.top; int deltaLeft = startBounds.left - finalBounds.left; photoView.setPivotY( (photoView.getHeight() - finalBounds.height()) / 2); photoView.setPivotX((photoView.getWidth() - finalBounds.width()) / 2); photoView.setScaleX(1 / startScale); photoView.setScaleY(1 / startScale); photoView.setTranslationX(deltaLeft); photoView.setTranslationY(deltaTop); photoView.animate().translationY(0).translationX(0) .scaleY(1) .scaleX(1).setDuration(ANIMATION_DURATION) .setInterpolator( new AccelerateDecelerateInterpolator()) .withEndAction(endAction); if (rect.type == AnimationRect.TYPE_EXTEND_V || rect.type == AnimationRect.TYPE_EXTEND_H) { AnimatorSet animationSet = new AnimatorSet(); animationSet.setDuration(ANIMATION_DURATION); animationSet .setInterpolator(new AccelerateDecelerateInterpolator()); animationSet.playTogether(ObjectAnimator.ofFloat(photoView, "clipBottom", thumbnailAndOriDeltaHeight, 0)); animationSet.start(); } else { AnimatorSet animationSet = new AnimatorSet(); animationSet.setDuration(ANIMATION_DURATION); animationSet .setInterpolator(new AccelerateDecelerateInterpolator()); float clipRectH = ((float) (oriBitmapScaledWidth - oriBitmapScaledWidth * thumbnailAndOriDeltaWidth - rect.widgetWidth) / 2) / (float) oriBitmapScaledWidth; float clipRectV = ((float) (oriBitmapScaledHeight - oriBitmapScaledHeight * thumbnailAndOriDeltaHeight - rect.widgetHeight) / 2) / (float) oriBitmapScaledHeight; animationSet.playTogether(ObjectAnimator.ofFloat(photoView, "clipHorizontal", clipRectH, 0)); animationSet.playTogether(ObjectAnimator.ofFloat(photoView, "clipVertical", clipRectV, 0)); animationSet.playTogether(ObjectAnimator.ofFloat(photoView, "clipBottom", thumbnailAndOriDeltaHeight, 0)); animationSet.playTogether(ObjectAnimator.ofFloat(photoView, "clipRight", thumbnailAndOriDeltaWidth, 0)); animationSet.start(); } photoView.getViewTreeObserver().removeOnPreDrawListener(this); return true; } }); return view; } public void animationExit(ObjectAnimator backgroundAnimator) { if (Math.abs(gifImageView.getScale() - 1.0f) > 0.1f) { gifImageView.setScale(1, true); return; } getActivity().overridePendingTransition(0, 0); animateClose(backgroundAnimator); } @SuppressLint("NewApi") private void animateClose(ObjectAnimator backgroundAnimator) { gifImageView.setVisibility(View.INVISIBLE); final ClipImageView photoView = (ClipImageView) getView().findViewById(R.id.cover); photoView.setVisibility(View.VISIBLE); AnimationRect rect = getArguments().getParcelable("rect"); if (rect == null) { photoView.animate().alpha(0); backgroundAnimator.start(); return; } final Rect startBounds = rect.scaledBitmapRect; final Rect finalBounds = AnimationUtility.getBitmapRectFromImageView(photoView); if (finalBounds == null) { photoView.animate().alpha(0); backgroundAnimator.start(); return; } if (Utility.isDevicePort() != rect.isScreenPortrait) { photoView.animate().alpha(0); backgroundAnimator.start(); return; } float startScale; if ((float) finalBounds.width() / finalBounds.height() > (float) startBounds.width() / startBounds.height()) { startScale = (float) startBounds.height() / finalBounds.height(); } else { startScale = (float) startBounds.width() / finalBounds.width(); } final float startScaleFinal = startScale; int oriBitmapScaledWidth = (int) (finalBounds.width() * startScale); int oriBitmapScaledHeight = (int) (finalBounds.height() * startScale); //sina server may cut thumbnail's right or bottom int thumbnailAndOriDeltaRightSize = Math .abs(rect.scaledBitmapRect.width() - oriBitmapScaledWidth); int thumbnailAndOriDeltaBottomSize = Math .abs(rect.scaledBitmapRect.height() - oriBitmapScaledHeight); float serverClipThumbnailRightSizePercent = (float) thumbnailAndOriDeltaRightSize / (float) oriBitmapScaledWidth; float serverClipThumbnailBottomSizePercent = (float) thumbnailAndOriDeltaBottomSize / (float) oriBitmapScaledHeight; int deltaTop = startBounds.top - finalBounds.top; int deltaLeft = startBounds.left - finalBounds.left; photoView.setPivotY((photoView.getHeight() - finalBounds.height()) / 2); photoView.setPivotX((photoView.getWidth() - finalBounds.width()) / 2); photoView.animate().translationX(deltaLeft).translationY(deltaTop) .scaleY(startScaleFinal) .scaleX(startScaleFinal).setDuration(ANIMATION_DURATION) .setInterpolator(new AccelerateDecelerateInterpolator()) .withEndAction(new Runnable() { @Override public void run() { photoView.animate().alpha(0.0f).setDuration(200).withEndAction( new Runnable() { @Override public void run() { } }); } }); if (rect.type == AnimationRect.TYPE_EXTEND_V || rect.type == AnimationRect.TYPE_EXTEND_H) { AnimatorSet animationSet = new AnimatorSet(); animationSet.setDuration(ANIMATION_DURATION); animationSet.setInterpolator(new AccelerateDecelerateInterpolator()); animationSet.playTogether(backgroundAnimator); animationSet.playTogether(ObjectAnimator.ofFloat(photoView, "clipBottom", 0, serverClipThumbnailBottomSizePercent)); animationSet.start(); } else { AnimatorSet animationSet = new AnimatorSet(); animationSet.setDuration(ANIMATION_DURATION); animationSet.setInterpolator(new AccelerateDecelerateInterpolator()); animationSet.playTogether(backgroundAnimator); float clipRectH = ((float) (oriBitmapScaledWidth - oriBitmapScaledWidth * serverClipThumbnailRightSizePercent - rect.widgetWidth) / 2) / (float) oriBitmapScaledWidth; float clipRectV = ((float) (oriBitmapScaledHeight - oriBitmapScaledHeight * serverClipThumbnailBottomSizePercent - rect.widgetHeight) / 2) / (float) oriBitmapScaledHeight; animationSet.playTogether(ObjectAnimator.ofFloat(photoView, "clipHorizontal", 0, clipRectH)); animationSet.playTogether(ObjectAnimator.ofFloat(photoView, "clipVertical", 0, clipRectV)); animationSet.playTogether(ObjectAnimator.ofFloat(photoView, "clipBottom", 0, serverClipThumbnailBottomSizePercent)); animationSet.playTogether(ObjectAnimator.ofFloat(photoView, "clipRight", 0, serverClipThumbnailRightSizePercent)); animationSet.start(); } } }