1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.transition; 17 18 import android.animation.Animator; 19 import android.animation.AnimatorListenerAdapter; 20 import android.animation.ObjectAnimator; 21 import android.animation.RectEvaluator; 22 import android.content.Context; 23 import android.graphics.Rect; 24 import android.util.AttributeSet; 25 import android.view.View; 26 import android.view.ViewGroup; 27 28 /** 29 * ChangeClipBounds captures the {@link android.view.View#getClipBounds()} before and after the 30 * scene change and animates those changes during the transition. 31 */ 32 public class ChangeClipBounds extends Transition { 33 34 private static final String TAG = "ChangeTransform"; 35 36 private static final String PROPNAME_CLIP = "android:clipBounds:clip"; 37 private static final String PROPNAME_BOUNDS = "android:clipBounds:bounds"; 38 39 private static final String[] sTransitionProperties = { 40 PROPNAME_CLIP, 41 }; 42 43 public ChangeClipBounds() {} 44 45 public ChangeClipBounds(Context context, AttributeSet attrs) { 46 super(context, attrs); 47 } 48 49 @Override 50 public String[] getTransitionProperties() { 51 return sTransitionProperties; 52 } 53 54 private void captureValues(TransitionValues values) { 55 View view = values.view; 56 if (view.getVisibility() == View.GONE) { 57 return; 58 } 59 60 Rect clip = view.getClipBounds(); 61 values.values.put(PROPNAME_CLIP, clip); 62 if (clip == null) { 63 Rect bounds = new Rect(0, 0, view.getWidth(), view.getHeight()); 64 values.values.put(PROPNAME_BOUNDS, bounds); 65 } 66 } 67 68 @Override 69 public void captureStartValues(TransitionValues transitionValues) { 70 captureValues(transitionValues); 71 } 72 73 @Override 74 public void captureEndValues(TransitionValues transitionValues) { 75 captureValues(transitionValues); 76 } 77 78 @Override 79 public Animator createAnimator(final ViewGroup sceneRoot, TransitionValues startValues, 80 TransitionValues endValues) { 81 if (startValues == null || endValues == null 82 || !startValues.values.containsKey(PROPNAME_CLIP) 83 || !endValues.values.containsKey(PROPNAME_CLIP)) { 84 return null; 85 } 86 Rect start = (Rect) startValues.values.get(PROPNAME_CLIP); 87 Rect end = (Rect) endValues.values.get(PROPNAME_CLIP); 88 boolean endIsNull = end == null; 89 if (start == null && end == null) { 90 return null; // No animation required since there is no clip. 91 } 92 93 if (start == null) { 94 start = (Rect) startValues.values.get(PROPNAME_BOUNDS); 95 } else if (end == null) { 96 end = (Rect) endValues.values.get(PROPNAME_BOUNDS); 97 } 98 if (start.equals(end)) { 99 return null; 100 } 101 102 endValues.view.setClipBounds(start); 103 RectEvaluator evaluator = new RectEvaluator(new Rect()); 104 ObjectAnimator animator = 105 ObjectAnimator.ofObject(endValues.view, "clipBounds", evaluator, start, end); 106 if (endIsNull) { 107 final View endView = endValues.view; 108 animator.addListener(new AnimatorListenerAdapter() { 109 @Override 110 public void onAnimationEnd(Animator animation) { 111 endView.setClipBounds(null); 112 } 113 }); 114 } 115 return animator; 116 } 117 } 118