14ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette/* 24ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette * Copyright (C) 2015 The Android Open Source Project 34ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette * 44ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette * Licensed under the Apache License, Version 2.0 (the "License"); 54ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette * you may not use this file except in compliance with the License. 64ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette * You may obtain a copy of the License at 74ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette * 84ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette * http://www.apache.org/licenses/LICENSE-2.0 94ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette * 104ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette * Unless required by applicable law or agreed to in writing, software 114ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette * distributed under the License is distributed on an "AS IS" BASIS, 124ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette * See the License for the specific language governing permissions and 144ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette * limitations under the License. 154ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette */ 164ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverettepackage com.android.internal.transition; 174ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 184ea5ee233022877c2e34ae83a48c24630f83713eAlan Viveretteimport android.animation.Animator; 194ea5ee233022877c2e34ae83a48c24630f83713eAlan Viveretteimport android.animation.AnimatorListenerAdapter; 204ea5ee233022877c2e34ae83a48c24630f83713eAlan Viveretteimport android.animation.AnimatorSet; 214ea5ee233022877c2e34ae83a48c24630f83713eAlan Viveretteimport android.animation.ObjectAnimator; 224ea5ee233022877c2e34ae83a48c24630f83713eAlan Viveretteimport android.animation.TimeInterpolator; 234ea5ee233022877c2e34ae83a48c24630f83713eAlan Viveretteimport android.animation.TypeEvaluator; 244ea5ee233022877c2e34ae83a48c24630f83713eAlan Viveretteimport android.content.Context; 254ea5ee233022877c2e34ae83a48c24630f83713eAlan Viveretteimport android.content.res.TypedArray; 264ea5ee233022877c2e34ae83a48c24630f83713eAlan Viveretteimport android.graphics.Rect; 274ea5ee233022877c2e34ae83a48c24630f83713eAlan Viveretteimport android.transition.TransitionValues; 284ea5ee233022877c2e34ae83a48c24630f83713eAlan Viveretteimport android.transition.Visibility; 294ea5ee233022877c2e34ae83a48c24630f83713eAlan Viveretteimport android.util.AttributeSet; 304ea5ee233022877c2e34ae83a48c24630f83713eAlan Viveretteimport android.util.Property; 314ea5ee233022877c2e34ae83a48c24630f83713eAlan Viveretteimport android.view.View; 324ea5ee233022877c2e34ae83a48c24630f83713eAlan Viveretteimport android.view.ViewGroup; 334ea5ee233022877c2e34ae83a48c24630f83713eAlan Viveretteimport android.view.animation.AnimationUtils; 344ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 354ea5ee233022877c2e34ae83a48c24630f83713eAlan Viveretteimport com.android.internal.R; 364ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 374ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette/** 384ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette * EpicenterTranslateClipReveal captures the clip bounds and translation values 394ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette * before and after the scene change and animates between those and the 404ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette * epicenter bounds during a visibility transition. 414ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette */ 424ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverettepublic class EpicenterTranslateClipReveal extends Visibility { 434ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette private static final String PROPNAME_CLIP = "android:epicenterReveal:clip"; 444ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette private static final String PROPNAME_BOUNDS = "android:epicenterReveal:bounds"; 454ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette private static final String PROPNAME_TRANSLATE_X = "android:epicenterReveal:translateX"; 464ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette private static final String PROPNAME_TRANSLATE_Y = "android:epicenterReveal:translateY"; 474ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette private static final String PROPNAME_TRANSLATE_Z = "android:epicenterReveal:translateZ"; 484ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette private static final String PROPNAME_Z = "android:epicenterReveal:z"; 494ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 504ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette private final TimeInterpolator mInterpolatorX; 514ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette private final TimeInterpolator mInterpolatorY; 524ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette private final TimeInterpolator mInterpolatorZ; 534ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 544ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette public EpicenterTranslateClipReveal() { 554ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette mInterpolatorX = null; 564ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette mInterpolatorY = null; 574ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette mInterpolatorZ = null; 584ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 594ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 604ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette public EpicenterTranslateClipReveal(Context context, AttributeSet attrs) { 614ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette super(context, attrs); 624ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 634ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final TypedArray a = context.obtainStyledAttributes(attrs, 644ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette R.styleable.EpicenterTranslateClipReveal, 0, 0); 654ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 664ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final int interpolatorX = a.getResourceId( 674ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette R.styleable.EpicenterTranslateClipReveal_interpolatorX, 0); 684ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette if (interpolatorX != 0) { 694ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette mInterpolatorX = AnimationUtils.loadInterpolator(context, interpolatorX); 704ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } else { 714ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette mInterpolatorX = TransitionConstants.LINEAR_OUT_SLOW_IN; 724ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 734ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 744ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final int interpolatorY = a.getResourceId( 754ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette R.styleable.EpicenterTranslateClipReveal_interpolatorY, 0); 764ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette if (interpolatorY != 0) { 774ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette mInterpolatorY = AnimationUtils.loadInterpolator(context, interpolatorY); 784ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } else { 794ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette mInterpolatorY = TransitionConstants.FAST_OUT_SLOW_IN; 804ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 814ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 824ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final int interpolatorZ = a.getResourceId( 834ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette R.styleable.EpicenterTranslateClipReveal_interpolatorZ, 0); 844ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette if (interpolatorZ != 0) { 854ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette mInterpolatorZ = AnimationUtils.loadInterpolator(context, interpolatorZ); 864ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } else { 874ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette mInterpolatorZ = TransitionConstants.FAST_OUT_SLOW_IN; 884ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 894ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 904ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette a.recycle(); 914ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 924ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 934ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette @Override 944ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette public void captureStartValues(TransitionValues transitionValues) { 954ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette super.captureStartValues(transitionValues); 964ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette captureValues(transitionValues); 974ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 984ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 994ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette @Override 1004ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette public void captureEndValues(TransitionValues transitionValues) { 1014ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette super.captureEndValues(transitionValues); 1024ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette captureValues(transitionValues); 1034ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 1044ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 1054ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette private void captureValues(TransitionValues values) { 1064ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final View view = values.view; 1074ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette if (view.getVisibility() == View.GONE) { 1084ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette return; 1094ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 1104ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 1114ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final Rect bounds = new Rect(0, 0, view.getWidth(), view.getHeight()); 1124ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette values.values.put(PROPNAME_BOUNDS, bounds); 1134ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette values.values.put(PROPNAME_TRANSLATE_X, view.getTranslationX()); 1144ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette values.values.put(PROPNAME_TRANSLATE_Y, view.getTranslationY()); 1154ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette values.values.put(PROPNAME_TRANSLATE_Z, view.getTranslationZ()); 1164ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette values.values.put(PROPNAME_Z, view.getZ()); 1174ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 1184ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final Rect clip = view.getClipBounds(); 1194ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette values.values.put(PROPNAME_CLIP, clip); 1204ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 1214ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 1224ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette @Override 1234ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette public Animator onAppear(ViewGroup sceneRoot, View view, 1244ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette TransitionValues startValues, TransitionValues endValues) { 1254ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette if (endValues == null) { 1264ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette return null; 1274ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 1284ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 1294ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final Rect endBounds = (Rect) endValues.values.get(PROPNAME_BOUNDS); 1304ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final Rect startBounds = getEpicenterOrCenter(endBounds); 1314ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final float startX = startBounds.centerX() - endBounds.centerX(); 1324ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final float startY = startBounds.centerY() - endBounds.centerY(); 1334ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final float startZ = 0 - (float) endValues.values.get(PROPNAME_Z); 1344ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 1354ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette // Translate the view to be centered on the epicenter. 1364ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette view.setTranslationX(startX); 1374ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette view.setTranslationY(startY); 1384ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette view.setTranslationZ(startZ); 1394ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 1404ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final float endX = (float) endValues.values.get(PROPNAME_TRANSLATE_X); 1414ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final float endY = (float) endValues.values.get(PROPNAME_TRANSLATE_Y); 1424ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final float endZ = (float) endValues.values.get(PROPNAME_TRANSLATE_Z); 1434ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 1444ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final Rect endClip = getBestRect(endValues); 1454ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final Rect startClip = getEpicenterOrCenter(endClip); 1464ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 1474ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette // Prepare the view. 1484ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette view.setClipBounds(startClip); 1494ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 1504ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final State startStateX = new State(startClip.left, startClip.right, startX); 1514ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final State endStateX = new State(endClip.left, endClip.right, endX); 1524ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final State startStateY = new State(startClip.top, startClip.bottom, startY); 1534ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final State endStateY = new State(endClip.top, endClip.bottom, endY); 1544ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 1554ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette return createRectAnimator(view, startStateX, startStateY, startZ, endStateX, endStateY, 1564ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette endZ, endValues, mInterpolatorX, mInterpolatorY, mInterpolatorZ); 1574ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 1584ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 1594ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette @Override 1604ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette public Animator onDisappear(ViewGroup sceneRoot, View view, 1614ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette TransitionValues startValues, TransitionValues endValues) { 1624ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette if (startValues == null) { 1634ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette return null; 1644ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 1654ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 1664ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final Rect startBounds = (Rect) endValues.values.get(PROPNAME_BOUNDS); 1674ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final Rect endBounds = getEpicenterOrCenter(startBounds); 1684ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final float endX = endBounds.centerX() - startBounds.centerX(); 1694ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final float endY = endBounds.centerY() - startBounds.centerY(); 1704ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final float endZ = 0 - (float) startValues.values.get(PROPNAME_Z); 1714ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 1724ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final float startX = (float) endValues.values.get(PROPNAME_TRANSLATE_X); 1734ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final float startY = (float) endValues.values.get(PROPNAME_TRANSLATE_Y); 1744ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final float startZ = (float) endValues.values.get(PROPNAME_TRANSLATE_Z); 1754ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 1764ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final Rect startClip = getBestRect(startValues); 1774ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final Rect endClip = getEpicenterOrCenter(startClip); 1784ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 1794ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette // Prepare the view. 1804ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette view.setClipBounds(startClip); 1814ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 1824ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final State startStateX = new State(startClip.left, startClip.right, startX); 1834ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final State endStateX = new State(endClip.left, endClip.right, endX); 1844ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final State startStateY = new State(startClip.top, startClip.bottom, startY); 1854ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final State endStateY = new State(endClip.top, endClip.bottom, endY); 1864ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 1874ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette return createRectAnimator(view, startStateX, startStateY, startZ, endStateX, endStateY, 1884ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette endZ, endValues, mInterpolatorX, mInterpolatorY, mInterpolatorZ); 1894ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 1904ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 1914ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette private Rect getEpicenterOrCenter(Rect bestRect) { 1924ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final Rect epicenter = getEpicenter(); 1934ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette if (epicenter != null) { 1944ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette return epicenter; 1954ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 1964ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 1974ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final int centerX = bestRect.centerX(); 1984ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final int centerY = bestRect.centerY(); 1994ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette return new Rect(centerX, centerY, centerX, centerY); 2004ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 2014ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 2024ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette private Rect getBestRect(TransitionValues values) { 2034ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final Rect clipRect = (Rect) values.values.get(PROPNAME_CLIP); 2044ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette if (clipRect == null) { 2054ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette return (Rect) values.values.get(PROPNAME_BOUNDS); 2064ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 2074ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette return clipRect; 2084ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 2094ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 2104ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette private static Animator createRectAnimator(final View view, State startX, State startY, 2114ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette float startZ, State endX, State endY, float endZ, TransitionValues endValues, 2124ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette TimeInterpolator interpolatorX, TimeInterpolator interpolatorY, 2134ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette TimeInterpolator interpolatorZ) { 2144ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final StateEvaluator evaluator = new StateEvaluator(); 2154ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 2164ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final ObjectAnimator animZ = ObjectAnimator.ofFloat(view, View.TRANSLATION_Z, startZ, endZ); 2174ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette if (interpolatorZ != null) { 2184ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette animZ.setInterpolator(interpolatorZ); 2194ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 2204ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 2214ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final StateProperty propX = new StateProperty(StateProperty.TARGET_X); 2224ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final ObjectAnimator animX = ObjectAnimator.ofObject(view, propX, evaluator, startX, endX); 2234ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette if (interpolatorX != null) { 2244ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette animX.setInterpolator(interpolatorX); 2254ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 2264ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 2274ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final StateProperty propY = new StateProperty(StateProperty.TARGET_Y); 2284ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final ObjectAnimator animY = ObjectAnimator.ofObject(view, propY, evaluator, startY, endY); 2294ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette if (interpolatorY != null) { 2304ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette animY.setInterpolator(interpolatorY); 2314ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 2324ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 2334ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final Rect terminalClip = (Rect) endValues.values.get(PROPNAME_CLIP); 2344ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final AnimatorListenerAdapter animatorListener = new AnimatorListenerAdapter() { 2354ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette @Override 2364ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette public void onAnimationEnd(Animator animation) { 2374ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette view.setClipBounds(terminalClip); 2384ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 2394ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette }; 2404ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 2414ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final AnimatorSet animSet = new AnimatorSet(); 2424ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette animSet.playTogether(animX, animY, animZ); 2434ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette animSet.addListener(animatorListener); 2444ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette return animSet; 2454ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 2464ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 2474ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette private static class State { 2484ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette int lower; 2494ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette int upper; 2504ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette float trans; 2514ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 2524ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette public State() {} 2534ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 2544ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette public State(int lower, int upper, float trans) { 2554ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette this.lower = lower; 2564ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette this.upper = upper; 2574ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette this.trans = trans; 2584ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 2594ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 2604ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 2614ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette private static class StateEvaluator implements TypeEvaluator<State> { 2624ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette private final State mTemp = new State(); 2634ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 2644ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette @Override 2654ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette public State evaluate(float fraction, State startValue, State endValue) { 2664ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette mTemp.upper = startValue.upper + (int) ((endValue.upper - startValue.upper) * fraction); 2674ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette mTemp.lower = startValue.lower + (int) ((endValue.lower - startValue.lower) * fraction); 2684ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette mTemp.trans = startValue.trans + (int) ((endValue.trans - startValue.trans) * fraction); 2694ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette return mTemp; 2704ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 2714ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 2724ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 2734ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette private static class StateProperty extends Property<View, State> { 2744ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette public static final char TARGET_X = 'x'; 2754ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette public static final char TARGET_Y = 'y'; 2764ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 2774ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette private final Rect mTempRect = new Rect(); 2784ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette private final State mTempState = new State(); 2794ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 2804ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette private final int mTargetDimension; 2814ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 2824ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette public StateProperty(char targetDimension) { 2834ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette super(State.class, "state_" + targetDimension); 2844ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 2854ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette mTargetDimension = targetDimension; 2864ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 2874ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 2884ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette @Override 2894ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette public State get(View object) { 2904ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final Rect tempRect = mTempRect; 2914ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette if (!object.getClipBounds(tempRect)) { 2924ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette tempRect.setEmpty(); 2934ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 2944ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final State tempState = mTempState; 2954ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette if (mTargetDimension == TARGET_X) { 2964ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette tempState.trans = object.getTranslationX(); 2974ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette tempState.lower = tempRect.left + (int) tempState.trans; 2984ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette tempState.upper = tempRect.right + (int) tempState.trans; 2994ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } else { 3004ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette tempState.trans = object.getTranslationY(); 3014ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette tempState.lower = tempRect.top + (int) tempState.trans; 3024ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette tempState.upper = tempRect.bottom + (int) tempState.trans; 3034ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 3044ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette return tempState; 3054ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 3064ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 3074ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette @Override 3084ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette public void set(View object, State value) { 3094ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette final Rect tempRect = mTempRect; 3104ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette if (object.getClipBounds(tempRect)) { 3114ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette if (mTargetDimension == TARGET_X) { 3124ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette tempRect.left = value.lower - (int) value.trans; 3134ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette tempRect.right = value.upper - (int) value.trans; 3144ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } else { 3154ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette tempRect.top = value.lower - (int) value.trans; 3164ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette tempRect.bottom = value.upper - (int) value.trans; 3174ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 3184ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette object.setClipBounds(tempRect); 3194ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 3204ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette 3214ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette if (mTargetDimension == TARGET_X) { 3224ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette object.setTranslationX(value.trans); 3234ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } else { 3244ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette object.setTranslationY(value.trans); 3254ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 3264ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 3274ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette } 3284ea5ee233022877c2e34ae83a48c24630f83713eAlan Viverette} 329