Home | History | Annotate | Download | only in transition
      1 /*
      2  * Copyright (C) 2017 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 
     17 package androidx.transition;
     18 
     19 import android.animation.Animator;
     20 import android.animation.AnimatorListenerAdapter;
     21 import android.animation.ObjectAnimator;
     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 import androidx.annotation.NonNull;
     29 import androidx.core.view.ViewCompat;
     30 
     31 /**
     32  * ChangeClipBounds captures the {@link android.view.View#getClipBounds()} before and after the
     33  * scene change and animates those changes during the transition.
     34  *
     35  * <p>Prior to API 18 this does nothing.</p>
     36  */
     37 public class ChangeClipBounds extends Transition {
     38 
     39     private static final String PROPNAME_CLIP = "android:clipBounds:clip";
     40     private static final String PROPNAME_BOUNDS = "android:clipBounds:bounds";
     41 
     42     private static final String[] sTransitionProperties = {
     43             PROPNAME_CLIP,
     44     };
     45 
     46     @Override
     47     public String[] getTransitionProperties() {
     48         return sTransitionProperties;
     49     }
     50 
     51     public ChangeClipBounds() {
     52     }
     53 
     54     public ChangeClipBounds(Context context, AttributeSet attrs) {
     55         super(context, attrs);
     56     }
     57 
     58     private void captureValues(TransitionValues values) {
     59         View view = values.view;
     60         if (view.getVisibility() == View.GONE) {
     61             return;
     62         }
     63 
     64         Rect clip = ViewCompat.getClipBounds(view);
     65         values.values.put(PROPNAME_CLIP, clip);
     66         if (clip == null) {
     67             Rect bounds = new Rect(0, 0, view.getWidth(), view.getHeight());
     68             values.values.put(PROPNAME_BOUNDS, bounds);
     69         }
     70     }
     71 
     72     @Override
     73     public void captureStartValues(@NonNull TransitionValues transitionValues) {
     74         captureValues(transitionValues);
     75     }
     76 
     77     @Override
     78     public void captureEndValues(@NonNull TransitionValues transitionValues) {
     79         captureValues(transitionValues);
     80     }
     81 
     82     @Override
     83     public Animator createAnimator(@NonNull final ViewGroup sceneRoot, TransitionValues startValues,
     84             TransitionValues endValues) {
     85         if (startValues == null || endValues == null
     86                 || !startValues.values.containsKey(PROPNAME_CLIP)
     87                 || !endValues.values.containsKey(PROPNAME_CLIP)) {
     88             return null;
     89         }
     90         Rect start = (Rect) startValues.values.get(PROPNAME_CLIP);
     91         Rect end = (Rect) endValues.values.get(PROPNAME_CLIP);
     92         final boolean endIsNull = end == null;
     93         if (start == null && end == null) {
     94             return null; // No animation required since there is no clip.
     95         }
     96 
     97         if (start == null) {
     98             start = (Rect) startValues.values.get(PROPNAME_BOUNDS);
     99         } else if (end == null) {
    100             end = (Rect) endValues.values.get(PROPNAME_BOUNDS);
    101         }
    102         if (start.equals(end)) {
    103             return null;
    104         }
    105 
    106         ViewCompat.setClipBounds(endValues.view, start);
    107         RectEvaluator evaluator = new RectEvaluator(new Rect());
    108         ObjectAnimator animator = ObjectAnimator.ofObject(endValues.view, ViewUtils.CLIP_BOUNDS,
    109                 evaluator, start, end);
    110         if (endIsNull) {
    111             final View endView = endValues.view;
    112             animator.addListener(new AnimatorListenerAdapter() {
    113                 @Override
    114                 public void onAnimationEnd(Animator animation) {
    115                     ViewCompat.setClipBounds(endView, null);
    116                 }
    117             });
    118         }
    119         return animator;
    120     }
    121 }
    122