1faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase/* 2faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * Copyright (C) 2013 The Android Open Source Project 3faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * 4faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * Licensed under the Apache License, Version 2.0 (the "License"); 5faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * you may not use this file except in compliance with the License. 6faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * You may obtain a copy of the License at 7faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * 8faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * http://www.apache.org/licenses/LICENSE-2.0 9faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * 10faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * Unless required by applicable law or agreed to in writing, software 11faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * distributed under the License is distributed on an "AS IS" BASIS, 12faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * See the License for the specific language governing permissions and 14faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * limitations under the License. 15faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase */ 166ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase 17d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haasepackage android.transition; 18faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase 19d359952459f96a9b57f50a7434b8660836c6e987George Mountimport android.animation.AnimatorSet; 20ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mountimport android.content.Context; 21b7573c2dbaff442a0f9f814bdc05aaa685574870George Mountimport android.content.res.TypedArray; 22ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mountimport android.graphics.PointF; 23ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount 24faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.animation.Animator; 25faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.animation.AnimatorListenerAdapter; 26faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.animation.ObjectAnimator; 27faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.animation.PropertyValuesHolder; 28faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.animation.RectEvaluator; 29faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.graphics.Bitmap; 30faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.graphics.Canvas; 31ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mountimport android.graphics.Path; 32faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.graphics.Rect; 33faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.graphics.drawable.BitmapDrawable; 34ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mountimport android.graphics.drawable.Drawable; 35ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mountimport android.util.AttributeSet; 36ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mountimport android.util.Property; 37faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.view.View; 38faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.view.ViewGroup; 39faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase 40b7573c2dbaff442a0f9f814bdc05aaa685574870George Mountimport com.android.internal.R; 41b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount 4208735185f8105710e18ad02297461bec9268e514Chet Haaseimport java.util.Map; 43faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase 44faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase/** 45faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * This transition captures the layout bounds of target views before and after 46faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * the scene change and animates those changes during the transition. 47d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * 48d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * <p>A ChangeBounds transition can be described in a resource file by using the 49b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount * tag <code>changeBounds</code>, using its attributes of 50b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount * {@link android.R.styleable#ChangeBounds} along with the other standard 51d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * attributes of {@link android.R.styleable#Transition}.</p> 52faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase */ 53d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haasepublic class ChangeBounds extends Transition { 54faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase 55d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase private static final String PROPNAME_BOUNDS = "android:changeBounds:bounds"; 56b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount private static final String PROPNAME_CLIP = "android:changeBounds:clip"; 57d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase private static final String PROPNAME_PARENT = "android:changeBounds:parent"; 58d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase private static final String PROPNAME_WINDOW_X = "android:changeBounds:windowX"; 59d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase private static final String PROPNAME_WINDOW_Y = "android:changeBounds:windowY"; 60af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase private static final String[] sTransitionProperties = { 61199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase PROPNAME_BOUNDS, 62b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount PROPNAME_CLIP, 63199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase PROPNAME_PARENT, 64199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase PROPNAME_WINDOW_X, 65199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase PROPNAME_WINDOW_Y 66199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase }; 67199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase 68ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount private static final Property<Drawable, PointF> DRAWABLE_ORIGIN_PROPERTY = 69ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount new Property<Drawable, PointF>(PointF.class, "boundsOrigin") { 70ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount private Rect mBounds = new Rect(); 71ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount 72ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount @Override 73ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount public void set(Drawable object, PointF value) { 74ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount object.copyBounds(mBounds); 75ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount mBounds.offsetTo(Math.round(value.x), Math.round(value.y)); 76ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount object.setBounds(mBounds); 77ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount } 78ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount 79ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount @Override 80ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount public PointF get(Drawable object) { 81ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount object.copyBounds(mBounds); 82ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount return new PointF(mBounds.left, mBounds.top); 83ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount } 84ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount }; 85ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount 86d359952459f96a9b57f50a7434b8660836c6e987George Mount private static final Property<ViewBounds, PointF> TOP_LEFT_PROPERTY = 87d359952459f96a9b57f50a7434b8660836c6e987George Mount new Property<ViewBounds, PointF>(PointF.class, "topLeft") { 88d359952459f96a9b57f50a7434b8660836c6e987George Mount @Override 89d359952459f96a9b57f50a7434b8660836c6e987George Mount public void set(ViewBounds viewBounds, PointF topLeft) { 90d359952459f96a9b57f50a7434b8660836c6e987George Mount viewBounds.setTopLeft(topLeft); 91d359952459f96a9b57f50a7434b8660836c6e987George Mount } 92d359952459f96a9b57f50a7434b8660836c6e987George Mount 93d359952459f96a9b57f50a7434b8660836c6e987George Mount @Override 94d359952459f96a9b57f50a7434b8660836c6e987George Mount public PointF get(ViewBounds viewBounds) { 95d359952459f96a9b57f50a7434b8660836c6e987George Mount return null; 96d359952459f96a9b57f50a7434b8660836c6e987George Mount } 97d359952459f96a9b57f50a7434b8660836c6e987George Mount }; 98d359952459f96a9b57f50a7434b8660836c6e987George Mount 99d359952459f96a9b57f50a7434b8660836c6e987George Mount private static final Property<ViewBounds, PointF> BOTTOM_RIGHT_PROPERTY = 100d359952459f96a9b57f50a7434b8660836c6e987George Mount new Property<ViewBounds, PointF>(PointF.class, "bottomRight") { 101d359952459f96a9b57f50a7434b8660836c6e987George Mount @Override 102d359952459f96a9b57f50a7434b8660836c6e987George Mount public void set(ViewBounds viewBounds, PointF bottomRight) { 103d359952459f96a9b57f50a7434b8660836c6e987George Mount viewBounds.setBottomRight(bottomRight); 104d359952459f96a9b57f50a7434b8660836c6e987George Mount } 105d359952459f96a9b57f50a7434b8660836c6e987George Mount 106d359952459f96a9b57f50a7434b8660836c6e987George Mount @Override 107d359952459f96a9b57f50a7434b8660836c6e987George Mount public PointF get(ViewBounds viewBounds) { 108d359952459f96a9b57f50a7434b8660836c6e987George Mount return null; 109d359952459f96a9b57f50a7434b8660836c6e987George Mount } 110d359952459f96a9b57f50a7434b8660836c6e987George Mount }; 111d359952459f96a9b57f50a7434b8660836c6e987George Mount 112b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount private static final Property<View, PointF> BOTTOM_RIGHT_ONLY_PROPERTY = 113b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount new Property<View, PointF>(PointF.class, "bottomRight") { 114b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount @Override 115b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount public void set(View view, PointF bottomRight) { 116b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount int left = view.getLeft(); 117b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount int top = view.getTop(); 118b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount int right = Math.round(bottomRight.x); 119b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount int bottom = Math.round(bottomRight.y); 120b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount view.setLeftTopRightBottom(left, top, right, bottom); 121b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount } 122b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount 123b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount @Override 124b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount public PointF get(View view) { 125b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount return null; 126b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount } 127b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount }; 128b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount 129b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount private static final Property<View, PointF> TOP_LEFT_ONLY_PROPERTY = 130b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount new Property<View, PointF>(PointF.class, "topLeft") { 131b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount @Override 132b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount public void set(View view, PointF topLeft) { 133b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount int left = Math.round(topLeft.x); 134b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount int top = Math.round(topLeft.y); 135b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount int right = view.getRight(); 136b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount int bottom = view.getBottom(); 137b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount view.setLeftTopRightBottom(left, top, right, bottom); 138b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount } 139b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount 140b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount @Override 141b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount public PointF get(View view) { 142b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount return null; 143b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount } 144b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount }; 145b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount 146b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount private static final Property<View, PointF> POSITION_PROPERTY = 147b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount new Property<View, PointF>(PointF.class, "position") { 148b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount @Override 149b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount public void set(View view, PointF topLeft) { 150b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount int left = Math.round(topLeft.x); 151b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount int top = Math.round(topLeft.y); 152b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount int right = left + view.getWidth(); 153b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount int bottom = top + view.getHeight(); 154b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount view.setLeftTopRightBottom(left, top, right, bottom); 155b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount } 156b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount 157b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount @Override 158b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount public PointF get(View view) { 159b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount return null; 160b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount } 161b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount }; 162b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount 163faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase int[] tempLocation = new int[2]; 164faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase boolean mResizeClip = false; 165faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase boolean mReparent = false; 166d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase private static final String LOG_TAG = "ChangeBounds"; 167faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase 168faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase private static RectEvaluator sRectEvaluator = new RectEvaluator(); 169faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase 170ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount public ChangeBounds() {} 171ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount 172ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount public ChangeBounds(Context context, AttributeSet attrs) { 173ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount super(context, attrs); 174b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount 175b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ChangeBounds); 176b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount boolean resizeClip = a.getBoolean(R.styleable.ChangeBounds_resizeClip, false); 177b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount a.recycle(); 178b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount setResizeClip(resizeClip); 179ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount } 180ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount 181199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase @Override 182199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase public String[] getTransitionProperties() { 183199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase return sTransitionProperties; 184199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase } 185199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase 186b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount /** 187b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount * When <code>resizeClip</code> is true, ChangeBounds resizes the view using the clipBounds 188b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount * instead of changing the dimensions of the view during the animation. When 189b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount * <code>resizeClip</code> is false, ChangeBounds resizes the View by changing its dimensions. 190b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount * 191b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount * <p>When resizeClip is set to true, the clip bounds is modified by ChangeBounds. Therefore, 192b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount * {@link android.transition.ChangeClipBounds} is not compatible with ChangeBounds 193b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount * in this mode.</p> 194b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount * 195b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount * @param resizeClip Used to indicate whether the view bounds should be modified or the 196b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount * clip bounds should be modified by ChangeBounds. 197b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount * @see android.view.View#setClipBounds(android.graphics.Rect) 198b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount * @attr ref android.R.styleable#ChangeBounds_resizeClip 199b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount */ 200faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase public void setResizeClip(boolean resizeClip) { 201faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase mResizeClip = resizeClip; 202faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 203faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase 204faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase /** 205b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount * Returns true when the ChangeBounds will resize by changing the clip bounds during the 206b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount * view animation or false when bounds are changed. The default value is false. 207b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount * 208b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount * @return true when the ChangeBounds will resize by changing the clip bounds during the 209b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount * view animation or false when bounds are changed. The default value is false. 210b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount * @attr ref android.R.styleable#ChangeBounds_resizeClip 211b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount */ 212b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount public boolean getResizeClip() { 213b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount return mResizeClip; 214b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount } 215b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount 216b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount /** 217d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * Setting this flag tells ChangeBounds to track the before/after parent 218faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * of every view using this transition. The flag is not enabled by 219faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * default because it requires the parent instances to be the same 220faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * in the two scenes or else all parents must use ids to allow 221faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * the transition to determine which parents are the same. 222faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * 223faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * @param reparent true if the transition should track the parent 224faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * container of target views and animate parent changes. 225c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu * @deprecated Use {@link android.transition.ChangeTransform} to handle 226c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu * transitions between different parents. 227faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase */ 228faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase public void setReparent(boolean reparent) { 229faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase mReparent = reparent; 230faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 231faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase 232d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase private void captureValues(TransitionValues values) { 233faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase View view = values.view; 234f791703f9bc566bee4f4809910d09dd415342078Chris Craik 2355ac9b20b41f72baabcb8a7d114bcaac3ed37e352George Mount if (view.isLaidOut() || view.getWidth() != 0 || view.getHeight() != 0) { 236f791703f9bc566bee4f4809910d09dd415342078Chris Craik values.values.put(PROPNAME_BOUNDS, new Rect(view.getLeft(), view.getTop(), 237f791703f9bc566bee4f4809910d09dd415342078Chris Craik view.getRight(), view.getBottom())); 238f791703f9bc566bee4f4809910d09dd415342078Chris Craik values.values.put(PROPNAME_PARENT, values.view.getParent()); 239f791703f9bc566bee4f4809910d09dd415342078Chris Craik if (mReparent) { 240f791703f9bc566bee4f4809910d09dd415342078Chris Craik values.view.getLocationInWindow(tempLocation); 241f791703f9bc566bee4f4809910d09dd415342078Chris Craik values.values.put(PROPNAME_WINDOW_X, tempLocation[0]); 242f791703f9bc566bee4f4809910d09dd415342078Chris Craik values.values.put(PROPNAME_WINDOW_Y, tempLocation[1]); 243f791703f9bc566bee4f4809910d09dd415342078Chris Craik } 244b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount if (mResizeClip) { 245b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount values.values.put(PROPNAME_CLIP, view.getClipBounds()); 246b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount } 2474d1ecf5daf6ad0b5420f3f3657e2cbaeea630240George Mount } 248faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 249faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase 250faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase @Override 251d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase public void captureStartValues(TransitionValues transitionValues) { 252d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase captureValues(transitionValues); 253d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase } 254d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase 255d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase @Override 256d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase public void captureEndValues(TransitionValues transitionValues) { 257d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase captureValues(transitionValues); 258d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase } 259d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase 2604d1ecf5daf6ad0b5420f3f3657e2cbaeea630240George Mount private boolean parentMatches(View startParent, View endParent) { 2614d1ecf5daf6ad0b5420f3f3657e2cbaeea630240George Mount boolean parentMatches = true; 2624d1ecf5daf6ad0b5420f3f3657e2cbaeea630240George Mount if (mReparent) { 2634d1ecf5daf6ad0b5420f3f3657e2cbaeea630240George Mount TransitionValues endValues = getMatchedTransitionValues(startParent, true); 2644d1ecf5daf6ad0b5420f3f3657e2cbaeea630240George Mount if (endValues == null) { 2654d1ecf5daf6ad0b5420f3f3657e2cbaeea630240George Mount parentMatches = startParent == endParent; 2664d1ecf5daf6ad0b5420f3f3657e2cbaeea630240George Mount } else { 2674d1ecf5daf6ad0b5420f3f3657e2cbaeea630240George Mount parentMatches = endParent == endValues.view; 2684d1ecf5daf6ad0b5420f3f3657e2cbaeea630240George Mount } 2694d1ecf5daf6ad0b5420f3f3657e2cbaeea630240George Mount } 2704d1ecf5daf6ad0b5420f3f3657e2cbaeea630240George Mount return parentMatches; 2714d1ecf5daf6ad0b5420f3f3657e2cbaeea630240George Mount } 2724d1ecf5daf6ad0b5420f3f3657e2cbaeea630240George Mount 273d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase @Override 274d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase public Animator createAnimator(final ViewGroup sceneRoot, TransitionValues startValues, 275faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase TransitionValues endValues) { 276faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase if (startValues == null || endValues == null) { 277faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase return null; 278faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 2792ea7f8b9c5f903050d42c1af57406bf528979f45Chet Haase Map<String, Object> startParentVals = startValues.values; 2802ea7f8b9c5f903050d42c1af57406bf528979f45Chet Haase Map<String, Object> endParentVals = endValues.values; 2812ea7f8b9c5f903050d42c1af57406bf528979f45Chet Haase ViewGroup startParent = (ViewGroup) startParentVals.get(PROPNAME_PARENT); 2822ea7f8b9c5f903050d42c1af57406bf528979f45Chet Haase ViewGroup endParent = (ViewGroup) endParentVals.get(PROPNAME_PARENT); 283faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase if (startParent == null || endParent == null) { 284faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase return null; 285faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 2862ea7f8b9c5f903050d42c1af57406bf528979f45Chet Haase final View view = endValues.view; 2874d1ecf5daf6ad0b5420f3f3657e2cbaeea630240George Mount if (parentMatches(startParent, endParent)) { 288faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase Rect startBounds = (Rect) startValues.values.get(PROPNAME_BOUNDS); 289faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase Rect endBounds = (Rect) endValues.values.get(PROPNAME_BOUNDS); 290b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount final int startLeft = startBounds.left; 291b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount final int endLeft = endBounds.left; 292b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount final int startTop = startBounds.top; 293b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount final int endTop = endBounds.top; 294b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount final int startRight = startBounds.right; 295b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount final int endRight = endBounds.right; 296b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount final int startBottom = startBounds.bottom; 297b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount final int endBottom = endBounds.bottom; 298b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount final int startWidth = startRight - startLeft; 299b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount final int startHeight = startBottom - startTop; 300b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount final int endWidth = endRight - endLeft; 301b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount final int endHeight = endBottom - endTop; 302b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount Rect startClip = (Rect) startValues.values.get(PROPNAME_CLIP); 303b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount Rect endClip = (Rect) endValues.values.get(PROPNAME_CLIP); 304faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase int numChanges = 0; 3052cacfe3a98ff4f777503cedca5e6fc44e6df269fGeorge Mount if ((startWidth != 0 && startHeight != 0) || (endWidth != 0 && endHeight != 0)) { 306ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount if (startLeft != endLeft || startTop != endTop) ++numChanges; 307ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount if (startRight != endRight || startBottom != endBottom) ++numChanges; 308faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 309b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount if ((startClip != null && !startClip.equals(endClip)) || 310b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount (startClip == null && endClip != null)) { 311b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount ++numChanges; 312b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount } 313faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase if (numChanges > 0) { 314b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount Animator anim; 315faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase if (!mResizeClip) { 316d359952459f96a9b57f50a7434b8660836c6e987George Mount view.setLeftTopRightBottom(startLeft, startTop, startRight, startBottom); 317b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount if (numChanges == 2) { 318b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount if (startWidth == endWidth && startHeight == endHeight) { 319b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount Path topLeftPath = getPathMotion().getPath(startLeft, startTop, endLeft, 320b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount endTop); 321b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount anim = ObjectAnimator.ofObject(view, POSITION_PROPERTY, null, 322b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount topLeftPath); 323b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount } else { 324b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount final ViewBounds viewBounds = new ViewBounds(view); 325b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount Path topLeftPath = getPathMotion().getPath(startLeft, startTop, 326b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount endLeft, endTop); 327b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount ObjectAnimator topLeftAnimator = ObjectAnimator 328b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount .ofObject(viewBounds, TOP_LEFT_PROPERTY, null, topLeftPath); 329b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount 330b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount Path bottomRightPath = getPathMotion().getPath(startRight, startBottom, 331b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount endRight, endBottom); 332b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount ObjectAnimator bottomRightAnimator = ObjectAnimator.ofObject(viewBounds, 333b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount BOTTOM_RIGHT_PROPERTY, null, bottomRightPath); 334b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount AnimatorSet set = new AnimatorSet(); 335b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount set.playTogether(topLeftAnimator, bottomRightAnimator); 336b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount anim = set; 337b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount set.addListener(new AnimatorListenerAdapter() { 338b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount // We need a strong reference to viewBounds until the 339b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount // animator ends. 340b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount private ViewBounds mViewBounds = viewBounds; 341b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount }); 342b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount } 343b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount } else if (startLeft != endLeft || startTop != endTop) { 344b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount Path topLeftPath = getPathMotion().getPath(startLeft, startTop, 345b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount endLeft, endTop); 346b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount anim = ObjectAnimator.ofObject(view, TOP_LEFT_ONLY_PROPERTY, null, 347b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount topLeftPath); 348b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount } else { 349b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount Path bottomRight = getPathMotion().getPath(startRight, startBottom, 350b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount endRight, endBottom); 351b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount anim = ObjectAnimator.ofObject(view, BOTTOM_RIGHT_ONLY_PROPERTY, null, 352b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount bottomRight); 353faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 354faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } else { 355b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount int maxWidth = Math.max(startWidth, endWidth); 356b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount int maxHeight = Math.max(startHeight, endHeight); 357b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount 358b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount view.setLeftTopRightBottom(startLeft, startTop, startLeft + maxWidth, 359b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount startTop + maxHeight); 360b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount 361b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount ObjectAnimator positionAnimator = null; 362b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount if (startLeft != endLeft || startTop != endTop) { 363b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount Path topLeftPath = getPathMotion().getPath(startLeft, startTop, endLeft, 364b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount endTop); 365b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount positionAnimator = ObjectAnimator.ofObject(view, POSITION_PROPERTY, null, 366b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount topLeftPath); 367b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount } 368b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount final Rect finalClip = endClip; 369b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount if (startClip == null) { 370b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount startClip = new Rect(0, 0, startWidth, startHeight); 371b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount } 372b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount if (endClip == null) { 373b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount endClip = new Rect(0, 0, endWidth, endHeight); 374faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 375ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount ObjectAnimator clipAnimator = null; 376b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount if (!startClip.equals(endClip)) { 377b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount view.setClipBounds(startClip); 378ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount clipAnimator = ObjectAnimator.ofObject(view, "clipBounds", sRectEvaluator, 379b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount startClip, endClip); 380b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount clipAnimator.addListener(new AnimatorListenerAdapter() { 381b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount private boolean mIsCanceled; 382199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase 383faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase @Override 384b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount public void onAnimationCancel(Animator animation) { 385b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount mIsCanceled = true; 386199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase } 387199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase 388199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase @Override 389b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount public void onAnimationEnd(Animator animation) { 390b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount if (!mIsCanceled) { 391b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount view.setClipBounds(finalClip); 392b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount view.setLeftTopRightBottom(endLeft, endTop, endRight, 393b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount endBottom); 394199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase } 395199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase } 396b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount }); 397b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount } 398b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount anim = TransitionUtils.mergeAnimators(positionAnimator, 399b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount clipAnimator); 400b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount } 401b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount if (view.getParent() instanceof ViewGroup) { 402b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount final ViewGroup parent = (ViewGroup) view.getParent(); 403b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount parent.suppressLayout(true); 404b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount TransitionListener transitionListener = new TransitionListenerAdapter() { 405b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount boolean mCanceled = false; 406199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase 407b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount @Override 408b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount public void onTransitionCancel(Transition transition) { 409b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount parent.suppressLayout(false); 410b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount mCanceled = true; 411b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount } 412b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount 413b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount @Override 414b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount public void onTransitionEnd(Transition transition) { 415b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount if (!mCanceled) { 416199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase parent.suppressLayout(false); 417199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase } 418b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount } 419b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount 420b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount @Override 421b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount public void onTransitionPause(Transition transition) { 422b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount parent.suppressLayout(false); 423b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount } 424199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase 425faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase @Override 426b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount public void onTransitionResume(Transition transition) { 427b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount parent.suppressLayout(true); 428faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 429b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount }; 430b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount addListener(transitionListener); 431faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 432b7573c2dbaff442a0f9f814bdc05aaa685574870George Mount return anim; 433faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 434faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } else { 435faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase int startX = (Integer) startValues.values.get(PROPNAME_WINDOW_X); 436faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase int startY = (Integer) startValues.values.get(PROPNAME_WINDOW_Y); 437faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase int endX = (Integer) endValues.values.get(PROPNAME_WINDOW_X); 438faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase int endY = (Integer) endValues.values.get(PROPNAME_WINDOW_Y); 439faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase // TODO: also handle size changes: check bounds and animate size changes 440faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase if (startX != endX || startY != endY) { 441faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase sceneRoot.getLocationInWindow(tempLocation); 442faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), 443faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase Bitmap.Config.ARGB_8888); 444faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase Canvas canvas = new Canvas(bitmap); 445faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase view.draw(canvas); 446faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase final BitmapDrawable drawable = new BitmapDrawable(bitmap); 447b5ef7f8c6d4629b2998de6c0b27bc1a4779b3e49George Mount final float transitionAlpha = view.getTransitionAlpha(); 448b5ef7f8c6d4629b2998de6c0b27bc1a4779b3e49George Mount view.setTransitionAlpha(0); 449faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase sceneRoot.getOverlay().add(drawable); 450ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount Path topLeftPath = getPathMotion().getPath(startX - tempLocation[0], 451ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount startY - tempLocation[1], endX - tempLocation[0], endY - tempLocation[1]); 452ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount PropertyValuesHolder origin = PropertyValuesHolder.ofObject( 453ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount DRAWABLE_ORIGIN_PROPERTY, null, topLeftPath); 454ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(drawable, origin); 455faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase anim.addListener(new AnimatorListenerAdapter() { 456faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase @Override 457faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase public void onAnimationEnd(Animator animation) { 458faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase sceneRoot.getOverlay().remove(drawable); 459b5ef7f8c6d4629b2998de6c0b27bc1a4779b3e49George Mount view.setTransitionAlpha(transitionAlpha); 460faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 461faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase }); 4622ea7f8b9c5f903050d42c1af57406bf528979f45Chet Haase return anim; 463faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 464faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 4652ea7f8b9c5f903050d42c1af57406bf528979f45Chet Haase return null; 466faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase } 467ff8e6d85dc5ef03b8d7c94b014fa4da800b5402cGeorge Mount 468d359952459f96a9b57f50a7434b8660836c6e987George Mount private static class ViewBounds { 469d359952459f96a9b57f50a7434b8660836c6e987George Mount private int mLeft; 470d359952459f96a9b57f50a7434b8660836c6e987George Mount private int mTop; 471d359952459f96a9b57f50a7434b8660836c6e987George Mount private int mRight; 472d359952459f96a9b57f50a7434b8660836c6e987George Mount private int mBottom; 473d359952459f96a9b57f50a7434b8660836c6e987George Mount private boolean mIsTopLeftSet; 474d359952459f96a9b57f50a7434b8660836c6e987George Mount private boolean mIsBottomRightSet; 475d359952459f96a9b57f50a7434b8660836c6e987George Mount private View mView; 476d359952459f96a9b57f50a7434b8660836c6e987George Mount 477d359952459f96a9b57f50a7434b8660836c6e987George Mount public ViewBounds(View view) { 478d359952459f96a9b57f50a7434b8660836c6e987George Mount mView = view; 479ff8e6d85dc5ef03b8d7c94b014fa4da800b5402cGeorge Mount } 480ff8e6d85dc5ef03b8d7c94b014fa4da800b5402cGeorge Mount 481d359952459f96a9b57f50a7434b8660836c6e987George Mount public void setTopLeft(PointF topLeft) { 482d359952459f96a9b57f50a7434b8660836c6e987George Mount mLeft = Math.round(topLeft.x); 483d359952459f96a9b57f50a7434b8660836c6e987George Mount mTop = Math.round(topLeft.y); 484d359952459f96a9b57f50a7434b8660836c6e987George Mount mIsTopLeftSet = true; 485d359952459f96a9b57f50a7434b8660836c6e987George Mount if (mIsBottomRightSet) { 486d359952459f96a9b57f50a7434b8660836c6e987George Mount setLeftTopRightBottom(); 487d359952459f96a9b57f50a7434b8660836c6e987George Mount } 488ff8e6d85dc5ef03b8d7c94b014fa4da800b5402cGeorge Mount } 489ff8e6d85dc5ef03b8d7c94b014fa4da800b5402cGeorge Mount 490d359952459f96a9b57f50a7434b8660836c6e987George Mount public void setBottomRight(PointF bottomRight) { 491d359952459f96a9b57f50a7434b8660836c6e987George Mount mRight = Math.round(bottomRight.x); 492d359952459f96a9b57f50a7434b8660836c6e987George Mount mBottom = Math.round(bottomRight.y); 493d359952459f96a9b57f50a7434b8660836c6e987George Mount mIsBottomRightSet = true; 494d359952459f96a9b57f50a7434b8660836c6e987George Mount if (mIsTopLeftSet) { 495d359952459f96a9b57f50a7434b8660836c6e987George Mount setLeftTopRightBottom(); 496d359952459f96a9b57f50a7434b8660836c6e987George Mount } 497ff8e6d85dc5ef03b8d7c94b014fa4da800b5402cGeorge Mount } 498ff8e6d85dc5ef03b8d7c94b014fa4da800b5402cGeorge Mount 499d359952459f96a9b57f50a7434b8660836c6e987George Mount private void setLeftTopRightBottom() { 500d359952459f96a9b57f50a7434b8660836c6e987George Mount mView.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 501d359952459f96a9b57f50a7434b8660836c6e987George Mount mIsTopLeftSet = false; 502d359952459f96a9b57f50a7434b8660836c6e987George Mount mIsBottomRightSet = false; 503ff8e6d85dc5ef03b8d7c94b014fa4da800b5402cGeorge Mount } 504ff8e6d85dc5ef03b8d7c94b014fa4da800b5402cGeorge Mount } 505faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase} 506