// "Therefore those skilled at the unorthodox // are infinite as heaven and earth, // inexhaustible as the great rivers. // When they come to an end, // they begin again, // like the days and months; // they die and are reborn, // like the four seasons." // // - Sun Tsu, // "The Art of War" package com.forfan.bigbang.cropper.handler; import android.graphics.Matrix; import android.graphics.RectF; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.Animation; import android.view.animation.Transformation; import android.widget.ImageView; /** * Animation to handle smooth cropping image matrix transformation change, specifically for zoom-in/out. */ final class CropImageAnimation extends Animation implements Animation.AnimationListener { //region: Fields and Consts private final ImageView mImageView; private final CropOverlayView mCropOverlayView; private final float[] mStartBoundPoints = new float[8]; private final float[] mEndBoundPoints = new float[8]; private final RectF mStartCropWindowRect = new RectF(); private final RectF mEndCropWindowRect = new RectF(); private final float[] mStartImageMatrix = new float[9]; private final float[] mEndImageMatrix = new float[9]; private final RectF mAnimRect = new RectF(); private final float[] mAnimPoints = new float[8]; private final float[] mAnimMatrix = new float[9]; //endregion public CropImageAnimation(ImageView cropImageView, CropOverlayView cropOverlayView) { mImageView = cropImageView; mCropOverlayView = cropOverlayView; setDuration(300); setFillAfter(true); setInterpolator(new AccelerateDecelerateInterpolator()); setAnimationListener(this); } public void setStartState(float[] boundPoints, Matrix imageMatrix) { reset(); System.arraycopy(boundPoints, 0, mStartBoundPoints, 0, 8); mStartCropWindowRect.set(mCropOverlayView.getCropWindowRect()); imageMatrix.getValues(mStartImageMatrix); } public void setEndState(float[] boundPoints, Matrix imageMatrix) { System.arraycopy(boundPoints, 0, mEndBoundPoints, 0, 8); mEndCropWindowRect.set(mCropOverlayView.getCropWindowRect()); imageMatrix.getValues(mEndImageMatrix); } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { mAnimRect.left = mStartCropWindowRect.left + (mEndCropWindowRect.left - mStartCropWindowRect.left) * interpolatedTime; mAnimRect.top = mStartCropWindowRect.top + (mEndCropWindowRect.top - mStartCropWindowRect.top) * interpolatedTime; mAnimRect.right = mStartCropWindowRect.right + (mEndCropWindowRect.right - mStartCropWindowRect.right) * interpolatedTime; mAnimRect.bottom = mStartCropWindowRect.bottom + (mEndCropWindowRect.bottom - mStartCropWindowRect.bottom) * interpolatedTime; mCropOverlayView.setCropWindowRect(mAnimRect); for (int i = 0; i < mAnimPoints.length; i++) { mAnimPoints[i] = mStartBoundPoints[i] + (mEndBoundPoints[i] - mStartBoundPoints[i]) * interpolatedTime; } mCropOverlayView.setBounds(mAnimPoints, mImageView.getWidth(), mImageView.getHeight()); for (int i = 0; i < mAnimMatrix.length; i++) { mAnimMatrix[i] = mStartImageMatrix[i] + (mEndImageMatrix[i] - mStartImageMatrix[i]) * interpolatedTime; } Matrix m = mImageView.getImageMatrix(); m.setValues(mAnimMatrix); mImageView.setImageMatrix(m); mImageView.invalidate(); mCropOverlayView.invalidate(); } @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { mImageView.clearAnimation(); } @Override public void onAnimationRepeat(Animation animation) { } }