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 
ChangeClipBounds()43     public ChangeClipBounds() {}
44 
ChangeClipBounds(Context context, AttributeSet attrs)45     public ChangeClipBounds(Context context, AttributeSet attrs) {
46         super(context, attrs);
47     }
48 
49     @Override
getTransitionProperties()50     public String[] getTransitionProperties() {
51         return sTransitionProperties;
52     }
53 
captureValues(TransitionValues values)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
captureStartValues(TransitionValues transitionValues)69     public void captureStartValues(TransitionValues transitionValues) {
70         captureValues(transitionValues);
71     }
72 
73     @Override
captureEndValues(TransitionValues transitionValues)74     public void captureEndValues(TransitionValues transitionValues) {
75         captureValues(transitionValues);
76     }
77 
78     @Override
createAnimator(final ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues)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