/* * Copyright (C) 2019 ByteDance Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.bytedance.scene.animation.interaction.scenetransition; import android.graphics.Matrix; import android.os.Build; import android.support.annotation.NonNull; import android.support.annotation.RequiresApi; import android.support.v4.util.Pair; import android.support.v4.view.ViewCompat; import android.util.Property; import android.view.View; import android.view.ViewGroup; import com.bytedance.scene.animation.interaction.evaluator.MatrixEvaluator; import com.bytedance.scene.animation.interaction.progressanimation.AnimatorFactory; import com.bytedance.scene.animation.interaction.progressanimation.InteractionAnimation; import com.bytedance.scene.animation.interaction.scenetransition.utils.SceneViewCompatUtils; /** * Created by JiangQi on 9/2/18. * * TODO: 1. It is not resolved temporarily: Parent clip by the rotation * 2. Use Path in transform */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public class ChangeTransform extends SceneTransition { private Pair<Float, Float> mDeltaTranslationX; private Pair<Float, Float> mDeltaTranslationY; private Pair<Float, Float> mDeltaTranslationZ; private Pair<Float, Float> mAlpha; private Pair<Float, Float> mRotate; private Pair<Float, Float> mRotateX; private Pair<Float, Float> mRotateY; private float mDstRotate; private Matrix mFromMatrix; private Matrix mToMatrix; private Transforms mTransforms; @Override public void captureValue(@NonNull View fromView, @NonNull View toView, @NonNull View animationView) { super.captureValue(fromView, toView, animationView); this.mTransforms = new Transforms(animationView); mDeltaTranslationX = Pair.create(fromView.getTranslationX(), toView.getTranslationX()); mDeltaTranslationY = Pair.create(fromView.getTranslationY(), toView.getTranslationY()); mDeltaTranslationZ = Pair.create(fromView.getTranslationZ(), toView.getTranslationZ()); mAlpha = Pair.create(fromView.getAlpha(), toView.getAlpha()); //返回 if (fromView == animationView) { ViewGroup mFromViewParent = (ViewGroup) mFromView.getParent(); ViewGroup mToViewParent = (ViewGroup) mToView.getParent(); Matrix fromViewParentMatrix = new Matrix(); SceneViewCompatUtils.transformMatrixToGlobal(mFromViewParent, fromViewParentMatrix); Matrix toViewParentMatrix = new Matrix(); SceneViewCompatUtils.transformMatrixToGlobal(mToViewParent, toViewParentMatrix); Matrix mFromViewMatrix = new Matrix(mFromView.getMatrix()); Matrix mToViewMatrix = new Matrix(mToView.getMatrix()); Matrix toLocal = new Matrix(); fromViewParentMatrix.invert(toLocal); mToViewMatrix.postTranslate(toView.getLeft(), toView.getTop()); mToViewMatrix.postConcat(toViewParentMatrix); mToViewMatrix.postConcat(toLocal); mToViewMatrix.postTranslate(-fromView.getLeft(), -fromView.getTop());//因为GhostView一上来就有一定的移动 this.mFromMatrix = mFromViewMatrix; this.mToMatrix = mToViewMatrix; setIdentityTransforms(mAnimationView); } else { ViewGroup mFromViewParent = (ViewGroup) mFromView.getParent(); ViewGroup mToViewParent = (ViewGroup) mToView.getParent(); Matrix fromViewParentMatrix = new Matrix(); SceneViewCompatUtils.transformMatrixToGlobal(mFromViewParent, fromViewParentMatrix); Matrix toViewParentMatrix = new Matrix(); SceneViewCompatUtils.transformMatrixToGlobal(mToViewParent, toViewParentMatrix); Matrix mFromViewMatrix = new Matrix(mFromView.getMatrix()); Matrix mToViewMatrix = new Matrix(mToView.getMatrix()); Matrix toLocal = new Matrix(); toViewParentMatrix.invert(toLocal); mFromViewMatrix.postTranslate(fromView.getLeft(), fromView.getTop()); mFromViewMatrix.postConcat(fromViewParentMatrix); mFromViewMatrix.postConcat(toLocal); mFromViewMatrix.postTranslate(-toView.getLeft(), -toView.getTop()); this.mFromMatrix = mFromViewMatrix; this.mToMatrix = mToViewMatrix; setIdentityTransforms(mAnimationView); } SceneViewCompatUtils.setAnimationMatrix(mAnimationView, mFromMatrix); // mRotate = Pair.create(aaa(fromMatrix), aaa(toMatrix)); mRotateX = Pair.create(fromView.getRotationX(), toView.getRotationX()); mRotateY = Pair.create(fromView.getRotationY(), toView.getRotationY()); mDstRotate = toView.getRotation(); } private float aaa(Matrix matrix) { float[] v = new float[9]; matrix.getValues(v); float rAngle = Math.round(Math.atan2(v[Matrix.MSKEW_X], v[Matrix.MSCALE_X]) * (180 / Math.PI)); return -rAngle; } public static float scaleValue(Matrix matrix) { float[] f = new float[9]; matrix.getValues(f); float scaleX = f[Matrix.MSCALE_X]; float scaleY = f[Matrix.MSCALE_Y]; return scaleX; } public static float[] translateValue(Matrix matrix) { float[] f = new float[9]; matrix.getValues(f); float translateX = f[Matrix.MTRANS_X]; float translateY = f[Matrix.MTRANS_Y]; return new float[]{translateX, translateY}; } @Override public InteractionAnimation getAnimation(boolean push) { AnimatorFactory<View, Matrix> animatorFactory = new AnimatorFactory<>(mAnimationView, new Property<View, Matrix>(Matrix.class, "matrix") { @Override public void set(View object, Matrix value) { SceneViewCompatUtils.setAnimationMatrix(object, value); } @Override public Matrix get(View object) { return null; } }, new MatrixEvaluator(), mFromMatrix, mToMatrix, null); return animatorFactory.toInteractionAnimation(); // return AnimationBuilder.of(mAnimationView) // .translationX(mDeltaTranslationX.first, mDeltaTranslationX.second) // .translationY(mDeltaTranslationY.first, mDeltaTranslationY.second) // .translationZ(mDeltaTranslationZ.first, mDeltaTranslationZ.second) // .scaleX(mScaleX.first, mScaleX.second) // .scaleY(mScaleY.first, mScaleY.second) // .alpha(mAlpha.first, mAlpha.second) // .rotation(mRotate.first, mRotate.second) // .rotationX(mRotateX.first, mRotateX.second) // .rotationY(mRotateY.first, mRotateY.second) // .build(); } @Override public void finish(boolean push) { SceneViewCompatUtils.setAnimationMatrix(mAnimationView, null); mTransforms.restore(mAnimationView); } private static void setIdentityTransforms(View view) { setTransforms(view, 0, 0, 0, 1, 1, 0, 0, 0); } private static void setTransforms(View view, float translationX, float translationY, float translationZ, float scaleX, float scaleY, float rotationX, float rotationY, float rotationZ) { view.setTranslationX(translationX); view.setTranslationY(translationY); ViewCompat.setTranslationZ(view, translationZ); view.setScaleX(scaleX); view.setScaleY(scaleY); view.setRotationX(rotationX); view.setRotationY(rotationY); view.setRotation(rotationZ); } private static class Transforms { final float mTranslationX; final float mTranslationY; final float mTranslationZ; final float mScaleX; final float mScaleY; final float mRotationX; final float mRotationY; final float mRotationZ; Transforms(View view) { mTranslationX = view.getTranslationX(); mTranslationY = view.getTranslationY(); mTranslationZ = ViewCompat.getTranslationZ(view); mScaleX = view.getScaleX(); mScaleY = view.getScaleY(); mRotationX = view.getRotationX(); mRotationY = view.getRotationY(); mRotationZ = view.getRotation(); } public void restore(View view) { setTransforms(view, mTranslationX, mTranslationY, mTranslationZ, mScaleX, mScaleY, mRotationX, mRotationY, mRotationZ); } @Override public boolean equals(Object that) { if (!(that instanceof Transforms)) { return false; } Transforms thatTransform = (Transforms) that; return thatTransform.mTranslationX == mTranslationX && thatTransform.mTranslationY == mTranslationY && thatTransform.mTranslationZ == mTranslationZ && thatTransform.mScaleX == mScaleX && thatTransform.mScaleY == mScaleY && thatTransform.mRotationX == mRotationX && thatTransform.mRotationY == mRotationY && thatTransform.mRotationZ == mRotationZ; } @Override public int hashCode() { int code = mTranslationX != +0.0f ? Float.floatToIntBits(mTranslationX) : 0; code = 31 * code + (mTranslationY != +0.0f ? Float.floatToIntBits(mTranslationY) : 0); code = 31 * code + (mTranslationZ != +0.0f ? Float.floatToIntBits(mTranslationZ) : 0); code = 31 * code + (mScaleX != +0.0f ? Float.floatToIntBits(mScaleX) : 0); code = 31 * code + (mScaleY != +0.0f ? Float.floatToIntBits(mScaleY) : 0); code = 31 * code + (mRotationX != +0.0f ? Float.floatToIntBits(mRotationX) : 0); code = 31 * code + (mRotationY != +0.0f ? Float.floatToIntBits(mRotationY) : 0); code = 31 * code + (mRotationZ != +0.0f ? Float.floatToIntBits(mRotationZ) : 0); return code; } } }