ChangeImageTransform.java revision 990205eada00ad3e575761d19607bb03e12f9aa3
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package android.transition; 17 18import android.animation.Animator; 19import android.animation.AnimatorListenerAdapter; 20import android.animation.ObjectAnimator; 21import android.animation.TypeEvaluator; 22import android.graphics.Matrix; 23import android.graphics.Rect; 24import android.graphics.drawable.Drawable; 25import android.util.Property; 26import android.view.View; 27import android.view.ViewGroup; 28import android.widget.ImageView; 29 30import java.util.Map; 31 32/** 33 * Transitions changes in ImageView {@link ImageView#setScaleType(ImageView.ScaleType)} as 34 * well as image scaling due to ImageView size changes. When combined with 35 * {@link android.transition.ChangeBounds}, an ImageView that changes size will 36 * scale smoothly. 37 */ 38public class ChangeImageTransform extends Transition { 39 40 private static final String TAG = "ChangeScaleType"; 41 42 private static final String PROPNAME_MATRIX = "android:changeScaleType:matrix"; 43 private static final String PROPNAME_BOUNDS = "android:changeScaleType:bounds"; 44 45 private static final String[] sTransitionProperties = { 46 PROPNAME_MATRIX, 47 PROPNAME_BOUNDS, 48 }; 49 50 private static TypeEvaluator<Matrix> NULL_MATRIX_EVALUATOR = new TypeEvaluator<Matrix>() { 51 @Override 52 public Matrix evaluate(float fraction, Matrix startValue, Matrix endValue) { 53 return null; 54 } 55 }; 56 57 private static Property<ImageView, Matrix> ANIMATED_TRANSFORM_PROPERTY 58 = new Property<ImageView, Matrix>(Matrix.class, "animatedTransform") { 59 @Override 60 public void set(ImageView object, Matrix value) { 61 object.animateTransform(value); 62 } 63 64 @Override 65 public Matrix get(ImageView object) { 66 return null; 67 } 68 }; 69 70 private void captureValues(TransitionValues transitionValues) { 71 View view = transitionValues.view; 72 if (!(view instanceof ImageView) || view.getVisibility() != View.VISIBLE) { 73 return; 74 } 75 ImageView imageView = (ImageView) view; 76 Drawable drawable = imageView.getDrawable(); 77 if (drawable == null) { 78 return; 79 } 80 Map<String, Object> values = transitionValues.values; 81 82 int left = view.getLeft(); 83 int top = view.getTop(); 84 int right = view.getRight(); 85 int bottom = view.getBottom(); 86 87 Rect bounds = new Rect(left, top, right, bottom); 88 values.put(PROPNAME_BOUNDS, bounds); 89 Matrix matrix; 90 ImageView.ScaleType scaleType = imageView.getScaleType(); 91 if (scaleType == ImageView.ScaleType.FIT_XY) { 92 matrix = imageView.getImageMatrix(); 93 if (!matrix.isIdentity()) { 94 matrix = new Matrix(matrix); 95 } else { 96 int drawableWidth = drawable.getIntrinsicWidth(); 97 int drawableHeight = drawable.getIntrinsicHeight(); 98 if (drawableWidth > 0 && drawableHeight > 0) { 99 float scaleX = ((float) bounds.width()) / drawableWidth; 100 float scaleY = ((float) bounds.height()) / drawableHeight; 101 matrix = new Matrix(); 102 matrix.setScale(scaleX, scaleY); 103 } else { 104 matrix = null; 105 } 106 } 107 } else { 108 matrix = new Matrix(imageView.getImageMatrix()); 109 } 110 values.put(PROPNAME_MATRIX, matrix); 111 } 112 113 @Override 114 public void captureStartValues(TransitionValues transitionValues) { 115 captureValues(transitionValues); 116 } 117 118 @Override 119 public void captureEndValues(TransitionValues transitionValues) { 120 captureValues(transitionValues); 121 } 122 123 @Override 124 public String[] getTransitionProperties() { 125 return sTransitionProperties; 126 } 127 128 /** 129 * Creates an Animator for ImageViews moving, changing dimensions, and/or changing 130 * {@link android.widget.ImageView.ScaleType}. 131 * 132 * @param sceneRoot The root of the transition hierarchy. 133 * @param startValues The values for a specific target in the start scene. 134 * @param endValues The values for the target in the end scene. 135 * @return An Animator to move an ImageView or null if the View is not an ImageView, 136 * the Drawable changed, the View is not VISIBLE, or there was no change. 137 */ 138 @Override 139 public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, 140 TransitionValues endValues) { 141 if (startValues == null || endValues == null) { 142 return null; 143 } 144 Rect startBounds = (Rect) startValues.values.get(PROPNAME_BOUNDS); 145 Rect endBounds = (Rect) endValues.values.get(PROPNAME_BOUNDS); 146 if (startBounds == null || endBounds == null) { 147 return null; 148 } 149 150 Matrix startMatrix = (Matrix) startValues.values.get(PROPNAME_MATRIX); 151 Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_MATRIX); 152 153 boolean matricesEqual = (startMatrix == null && endMatrix == null) || 154 (startMatrix != null && startMatrix.equals(endMatrix)); 155 156 if (startBounds.equals(endBounds) && matricesEqual) { 157 return null; 158 } 159 160 ImageView imageView = (ImageView) endValues.view; 161 Drawable drawable = imageView.getDrawable(); 162 int drawableWidth = drawable.getIntrinsicWidth(); 163 int drawableHeight = drawable.getIntrinsicHeight(); 164 165 ObjectAnimator animator; 166 if (drawableWidth == 0 || drawableHeight == 0) { 167 animator = createNullAnimator(imageView); 168 } else { 169 if (startMatrix == null) { 170 startMatrix = Matrix.IDENTITY_MATRIX; 171 } 172 if (endMatrix == null) { 173 endMatrix = Matrix.IDENTITY_MATRIX; 174 } 175 animator = createMatrixAnimator(imageView, startMatrix, endMatrix); 176 } 177 return animator; 178 } 179 180 private ObjectAnimator createNullAnimator(ImageView imageView) { 181 return ObjectAnimator.ofObject(imageView, ANIMATED_TRANSFORM_PROPERTY, 182 NULL_MATRIX_EVALUATOR, null, null); 183 } 184 185 private ObjectAnimator createMatrixAnimator(final ImageView imageView, Matrix startMatrix, 186 final Matrix endMatrix) { 187 ObjectAnimator animator = ObjectAnimator.ofObject(imageView, ANIMATED_TRANSFORM_PROPERTY, 188 new MatrixEvaluator(), startMatrix, endMatrix); 189 /* 190 AnimatorListenerAdapter listener = new AnimatorListenerAdapter() { 191 private Matrix mPausedMatrix; 192 193 @Override 194 public void onAnimationPause(Animator animation) { 195 if (mPausedMatrix == null) { 196 mPausedMatrix = new Matrix(); 197 } 198 Matrix imageMatrix = imageView.getImageMatrix(); 199 mPausedMatrix.set(imageMatrix); 200 imageView.animateTransform(endMatrix); 201 } 202 203 @Override 204 public void onAnimationResume(Animator animation) { 205 imageView.animateTransform(mPausedMatrix); 206 } 207 }; 208 animator.addPauseListener(listener); 209 */ 210 return animator; 211 } 212 213 private static class MatrixEvaluator implements TypeEvaluator<Matrix> { 214 215 float[] mTempStartValues = new float[9]; 216 217 float[] mTempEndValues = new float[9]; 218 219 Matrix mTempMatrix = new Matrix(); 220 221 @Override 222 public Matrix evaluate(float fraction, Matrix startValue, Matrix endValue) { 223 startValue.getValues(mTempStartValues); 224 endValue.getValues(mTempEndValues); 225 for (int i = 0; i < 9; i++) { 226 float diff = mTempEndValues[i] - mTempStartValues[i]; 227 mTempEndValues[i] = mTempStartValues[i] + (fraction * diff); 228 } 229 mTempMatrix.setValues(mTempEndValues); 230 return mTempMatrix; 231 } 232 } 233 234} 235