1c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki/* 2c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * Copyright (C) 2016 The Android Open Source Project 3c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * 4c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * Licensed under the Apache License, Version 2.0 (the "License"); 5c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * you may not use this file except in compliance with the License. 6c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * You may obtain a copy of the License at 7c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * 8c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * http://www.apache.org/licenses/LICENSE-2.0 9c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * 10c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * Unless required by applicable law or agreed to in writing, software 11c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * distributed under the License is distributed on an "AS IS" BASIS, 12c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * See the License for the specific language governing permissions and 14c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * limitations under the License. 15c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki */ 16c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 17c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakipackage android.support.transition; 18c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 19c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.animation.Animator; 20c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.animation.AnimatorListenerAdapter; 21c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.animation.ObjectAnimator; 22c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.animation.PropertyValuesHolder; 23c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.graphics.Bitmap; 24c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.graphics.Canvas; 25c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.graphics.Rect; 26c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.graphics.drawable.BitmapDrawable; 27c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.view.View; 28c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.view.ViewGroup; 29c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 30c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport java.util.Map; 31c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 32c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki/** 33c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * This transition captures the layout bounds of target views before and after 34c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * the scene change and animates those changes during the transition. 35c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * 36c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * <p>A ChangeBounds transition can be described in a resource file by using the 37c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * tag <code>changeBounds</code>, along with the other standard 38c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * attributes of {@link android.R.styleable#Transition}.</p> 39c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki */ 40c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiclass ChangeBoundsPort extends TransitionPort { 41c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 42c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki private static final String PROPNAME_BOUNDS = "android:changeBounds:bounds"; 43c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 44c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki private static final String PROPNAME_PARENT = "android:changeBounds:parent"; 45c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 46c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki private static final String PROPNAME_WINDOW_X = "android:changeBounds:windowX"; 47c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 48c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki private static final String PROPNAME_WINDOW_Y = "android:changeBounds:windowY"; 49c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 50c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki private static final String[] sTransitionProperties = { 51c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki PROPNAME_BOUNDS, 52c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki PROPNAME_PARENT, 53c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki PROPNAME_WINDOW_X, 54c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki PROPNAME_WINDOW_Y 55c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki }; 56c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 57c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki private static final String LOG_TAG = "ChangeBounds"; 58c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 59c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki private static RectEvaluator sRectEvaluator = new RectEvaluator(); 60c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 61c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int[] tempLocation = new int[2]; 62c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 63c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki boolean mResizeClip = false; 64c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 65c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki boolean mReparent = false; 66c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 67c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki @Override 68c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki public String[] getTransitionProperties() { 69c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki return sTransitionProperties; 70c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 71c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 72c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki public void setResizeClip(boolean resizeClip) { 73c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki mResizeClip = resizeClip; 74c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 75c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 76c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki /** 77c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * Setting this flag tells ChangeBounds to track the before/after parent 78c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * of every view using this transition. The flag is not enabled by 79c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * default because it requires the parent instances to be the same 80c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * in the two scenes or else all parents must use ids to allow 81c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * the transition to determine which parents are the same. 82c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * 83c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * @param reparent true if the transition should track the parent 84c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * container of target views and animate parent changes. 85c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki */ 86c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki public void setReparent(boolean reparent) { 87c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki mReparent = reparent; 88c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 89c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 90c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki private void captureValues(TransitionValues values) { 91c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki View view = values.view; 92c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki values.values.put(PROPNAME_BOUNDS, new Rect(view.getLeft(), view.getTop(), 93c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki view.getRight(), view.getBottom())); 94c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki values.values.put(PROPNAME_PARENT, values.view.getParent()); 95c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki values.view.getLocationInWindow(tempLocation); 96c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki values.values.put(PROPNAME_WINDOW_X, tempLocation[0]); 97c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki values.values.put(PROPNAME_WINDOW_Y, tempLocation[1]); 98c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 99c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 100c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki @Override 101c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki public void captureStartValues(TransitionValues transitionValues) { 102c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki captureValues(transitionValues); 103c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 104c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 105c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki @Override 106c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki public void captureEndValues(TransitionValues transitionValues) { 107c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki captureValues(transitionValues); 108c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 109c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 110c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki @Override 111c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki public Animator createAnimator(final ViewGroup sceneRoot, TransitionValues startValues, 112c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki TransitionValues endValues) { 113c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (startValues == null || endValues == null) { 114c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki return null; 115c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 116c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki Map<String, Object> startParentVals = startValues.values; 117c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki Map<String, Object> endParentVals = endValues.values; 118c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki ViewGroup startParent = (ViewGroup) startParentVals.get(PROPNAME_PARENT); 119c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki ViewGroup endParent = (ViewGroup) endParentVals.get(PROPNAME_PARENT); 120c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (startParent == null || endParent == null) { 121c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki return null; 122c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 123c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki final View view = endValues.view; 124c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki boolean parentsEqual = (startParent == endParent) || 125c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki (startParent.getId() == endParent.getId()); 126c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki // TODO: Might want reparenting to be separate/subclass transition, or at least 127c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki // triggered by a property on ChangeBounds. Otherwise, we're forcing the requirement that 128c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki // all parents in layouts have IDs to avoid layout-inflation resulting in a side-effect 129c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki // of reparenting the views. 130c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (!mReparent || parentsEqual) { 131c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki Rect startBounds = (Rect) startValues.values.get(PROPNAME_BOUNDS); 132c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki Rect endBounds = (Rect) endValues.values.get(PROPNAME_BOUNDS); 133c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int startLeft = startBounds.left; 134c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int endLeft = endBounds.left; 135c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int startTop = startBounds.top; 136c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int endTop = endBounds.top; 137c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int startRight = startBounds.right; 138c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int endRight = endBounds.right; 139c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int startBottom = startBounds.bottom; 140c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int endBottom = endBounds.bottom; 141c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int startWidth = startRight - startLeft; 142c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int startHeight = startBottom - startTop; 143c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int endWidth = endRight - endLeft; 144c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int endHeight = endBottom - endTop; 145c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int numChanges = 0; 146c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (startWidth != 0 && startHeight != 0 && endWidth != 0 && endHeight != 0) { 147c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (startLeft != endLeft) { 148c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki ++numChanges; 149c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 150c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (startTop != endTop) { 151c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki ++numChanges; 152c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 153c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (startRight != endRight) { 154c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki ++numChanges; 155c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 156c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (startBottom != endBottom) { 157c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki ++numChanges; 158c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 159c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 160c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (numChanges > 0) { 161c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (!mResizeClip) { 162c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki PropertyValuesHolder pvh[] = new PropertyValuesHolder[numChanges]; 163c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int pvhIndex = 0; 164c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (startLeft != endLeft) { 165c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki view.setLeft(startLeft); 166c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 167c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (startTop != endTop) { 168c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki view.setTop(startTop); 169c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 170c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (startRight != endRight) { 171c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki view.setRight(startRight); 172c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 173c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (startBottom != endBottom) { 174c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki view.setBottom(startBottom); 175c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 176c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (startLeft != endLeft) { 177c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki pvh[pvhIndex++] = PropertyValuesHolder.ofInt("left", startLeft, endLeft); 178c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 179c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (startTop != endTop) { 180c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki pvh[pvhIndex++] = PropertyValuesHolder.ofInt("top", startTop, endTop); 181c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 182c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (startRight != endRight) { 183c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki pvh[pvhIndex++] = PropertyValuesHolder.ofInt("right", 184c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki startRight, endRight); 185c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 186c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (startBottom != endBottom) { 187c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki pvh[pvhIndex++] = PropertyValuesHolder.ofInt("bottom", 188c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki startBottom, endBottom); 189c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 190c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(view, pvh); 191c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (view.getParent() instanceof ViewGroup) { 192c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki final ViewGroup parent = (ViewGroup) view.getParent(); 193c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki// parent.suppressLayout(true); 194c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki TransitionListener transitionListener = new TransitionListenerAdapter() { 195c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki boolean mCanceled = false; 196c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 197c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki @Override 198c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki public void onTransitionCancel(TransitionPort transition) { 199c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki// parent.suppressLayout(false); 200c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki mCanceled = true; 201c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 202c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 203c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki @Override 204c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki public void onTransitionEnd(TransitionPort transition) { 205c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (!mCanceled) { 206c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki// parent.suppressLayout(false); 207c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 208c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 209c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 210c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki @Override 211c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki public void onTransitionPause(TransitionPort transition) { 212c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki// parent.suppressLayout(false); 213c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 214c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 215c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki @Override 216c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki public void onTransitionResume(TransitionPort transition) { 217c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki// parent.suppressLayout(true); 218c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 219c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki }; 220c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki addListener(transitionListener); 221c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 222c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki return anim; 223c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } else { 224c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (startWidth != endWidth) { 225c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki view.setRight(endLeft + 226c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki Math.max(startWidth, endWidth)); 227c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 228c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (startHeight != endHeight) { 229c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki view.setBottom(endTop + 230c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki Math.max(startHeight, endHeight)); 231c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 232c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki // TODO: don't clobber TX/TY 233c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (startLeft != endLeft) { 234c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki view.setTranslationX(startLeft - endLeft); 235c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 236c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (startTop != endTop) { 237c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki view.setTranslationY(startTop - endTop); 238c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 239c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki // Animate location with translationX/Y and size with clip bounds 240c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki float transXDelta = endLeft - startLeft; 241c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki float transYDelta = endTop - startTop; 242c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int widthDelta = endWidth - startWidth; 243c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int heightDelta = endHeight - startHeight; 244c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki numChanges = 0; 245c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (transXDelta != 0) { 246c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki numChanges++; 247c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 248c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (transYDelta != 0) { 249c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki numChanges++; 250c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 251c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (widthDelta != 0 || heightDelta != 0) { 252c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki numChanges++; 253c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 254c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki PropertyValuesHolder pvh[] = new PropertyValuesHolder[numChanges]; 255c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int pvhIndex = 0; 256c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (transXDelta != 0) { 257c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki pvh[pvhIndex++] = PropertyValuesHolder.ofFloat("translationX", 258c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki view.getTranslationX(), 0); 259c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 260c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (transYDelta != 0) { 261c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki pvh[pvhIndex++] = PropertyValuesHolder.ofFloat("translationY", 262c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki view.getTranslationY(), 0); 263c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 264c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (widthDelta != 0 || heightDelta != 0) { 265c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki Rect tempStartBounds = new Rect(0, 0, startWidth, startHeight); 266c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki Rect tempEndBounds = new Rect(0, 0, endWidth, endHeight); 267c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki// pvh[pvhIndex++] = PropertyValuesHolder.ofObject("clipBounds", 268c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki// sRectEvaluator, tempStartBounds, tempEndBounds); 269c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 270c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(view, pvh); 271c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (view.getParent() instanceof ViewGroup) { 272c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki final ViewGroup parent = (ViewGroup) view.getParent(); 273c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki// parent.suppressLayout(true); 274c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki TransitionListener transitionListener = new TransitionListenerAdapter() { 275c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki boolean mCanceled = false; 276c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 277c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki @Override 278c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki public void onTransitionCancel(TransitionPort transition) { 279c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki// parent.suppressLayout(false); 280c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki mCanceled = true; 281c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 282c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 283c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki @Override 284c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki public void onTransitionEnd(TransitionPort transition) { 285c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (!mCanceled) { 286c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki// parent.suppressLayout(false); 287c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 288c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 289c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 290c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki @Override 291c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki public void onTransitionPause(TransitionPort transition) { 292c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki// parent.suppressLayout(false); 293c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 294c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki 295c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki @Override 296c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki public void onTransitionResume(TransitionPort transition) { 297c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki// parent.suppressLayout(true); 298c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 299c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki }; 300c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki addListener(transitionListener); 301c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 302c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki anim.addListener(new AnimatorListenerAdapter() { 303c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki @Override 304c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki public void onAnimationEnd(Animator animation) { 305c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki// view.setClipBounds(null); 306c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 307c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki }); 308c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki return anim; 309c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 310c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 311c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } else { 312c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int startX = (Integer) startValues.values.get(PROPNAME_WINDOW_X); 313c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int startY = (Integer) startValues.values.get(PROPNAME_WINDOW_Y); 314c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int endX = (Integer) endValues.values.get(PROPNAME_WINDOW_X); 315c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki int endY = (Integer) endValues.values.get(PROPNAME_WINDOW_Y); 316c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki // TODO: also handle size changes: check bounds and animate size changes 317c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki if (startX != endX || startY != endY) { 318c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki sceneRoot.getLocationInWindow(tempLocation); 319c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), 320c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki Bitmap.Config.ARGB_8888); 321c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki Canvas canvas = new Canvas(bitmap); 322c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki view.draw(canvas); 323c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki final BitmapDrawable drawable = new BitmapDrawable(bitmap); 324c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki view.setVisibility(View.INVISIBLE); 325c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki ViewOverlay.createFrom(sceneRoot).add(drawable); 326c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki// sceneRoot.getOverlay().add(drawable); 327c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki Rect startBounds1 = new Rect(startX - tempLocation[0], startY - tempLocation[1], 328c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki startX - tempLocation[0] + view.getWidth(), 329c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki startY - tempLocation[1] + view.getHeight()); 330c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki Rect endBounds1 = new Rect(endX - tempLocation[0], endY - tempLocation[1], 331c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki endX - tempLocation[0] + view.getWidth(), 332c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki endY - tempLocation[1] + view.getHeight()); 333c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki ObjectAnimator anim = ObjectAnimator.ofObject(drawable, "bounds", 334c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki sRectEvaluator, startBounds1, endBounds1); 335c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki anim.addListener(new AnimatorListenerAdapter() { 336c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki @Override 337c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki public void onAnimationEnd(Animator animation) { 338c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki ViewOverlay.createFrom(sceneRoot).remove(drawable); 339c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki// sceneRoot.getOverlay().remove(drawable); 340c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki view.setVisibility(View.VISIBLE); 341c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 342c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki }); 343c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki return anim; 344c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 345c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 346c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki return null; 347c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki } 348c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki} 349