Home | History | Annotate | Download | only in transition
      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.graphics.Rect;
     19 import android.util.FloatMath;
     20 import android.util.Log;
     21 import android.view.View;
     22 import android.view.ViewGroup;
     23 
     24 /**
     25  * A propagation that varies with the distance to the epicenter of the Transition
     26  * or center of the scene if no epicenter exists. When a View is visible in the
     27  * start of the transition, Views farther from the epicenter will transition
     28  * sooner than Views closer to the epicenter. When a View is not in the start
     29  * of the transition or is not visible at the start of the transition, it will
     30  * transition sooner when closer to the epicenter and later when farther from
     31  * the epicenter. This is the default TransitionPropagation used with
     32  * {@link android.transition.Explode}.
     33  */
     34 public class CircularPropagation extends VisibilityPropagation {
     35     private static final String TAG = "CircularPropagation";
     36 
     37     private float mPropagationSpeed = 3.0f;
     38 
     39     /**
     40      * Sets the speed at which transition propagation happens, relative to the duration of the
     41      * Transition. A <code>propagationSpeed</code> of 1 means that a View centered farthest from
     42      * the epicenter and View centered at the epicenter will have a difference
     43      * in start delay of approximately the duration of the Transition. A speed of 2 means the
     44      * start delay difference will be approximately half of the duration of the transition. A
     45      * value of 0 is illegal, but negative values will invert the propagation.
     46      *
     47      * @param propagationSpeed The speed at which propagation occurs, relative to the duration
     48      *                         of the transition. A speed of 4 means it works 4 times as fast
     49      *                         as the duration of the transition. May not be 0.
     50      */
     51     public void setPropagationSpeed(float propagationSpeed) {
     52         if (propagationSpeed == 0) {
     53             throw new IllegalArgumentException("propagationSpeed may not be 0");
     54         }
     55         mPropagationSpeed = propagationSpeed;
     56     }
     57 
     58     @Override
     59     public long getStartDelay(ViewGroup sceneRoot, Transition transition,
     60             TransitionValues startValues, TransitionValues endValues) {
     61         if (startValues == null && endValues == null) {
     62             return 0;
     63         }
     64         int directionMultiplier = 1;
     65         TransitionValues positionValues;
     66         if (endValues == null || getViewVisibility(startValues) == View.VISIBLE) {
     67             positionValues = startValues;
     68             directionMultiplier = -1;
     69         } else {
     70             positionValues = endValues;
     71         }
     72 
     73         int viewCenterX = getViewX(positionValues);
     74         int viewCenterY = getViewY(positionValues);
     75 
     76         Rect epicenter = transition.getEpicenter();
     77         int epicenterX;
     78         int epicenterY;
     79         if (epicenter != null) {
     80             epicenterX = epicenter.centerX();
     81             epicenterY = epicenter.centerY();
     82         } else {
     83             int[] loc = new int[2];
     84             sceneRoot.getLocationOnScreen(loc);
     85             epicenterX = Math.round(loc[0] + (sceneRoot.getWidth() / 2)
     86                     + sceneRoot.getTranslationX());
     87             epicenterY = Math.round(loc[1] + (sceneRoot.getHeight() / 2)
     88                     + sceneRoot.getTranslationY());
     89         }
     90         float distance = distance(viewCenterX, viewCenterY, epicenterX, epicenterY);
     91         float maxDistance = distance(0, 0, sceneRoot.getWidth(), sceneRoot.getHeight());
     92         float distanceFraction = distance/maxDistance;
     93 
     94         long duration = transition.getDuration();
     95         if (duration < 0) {
     96             duration = 300;
     97         }
     98 
     99         return Math.round(duration * directionMultiplier / mPropagationSpeed * distanceFraction);
    100     }
    101 
    102     private static float distance(float x1, float y1, float x2, float y2) {
    103         float x = x2 - x1;
    104         float y = y2 - y1;
    105         return FloatMath.sqrt((x * x) + (y * y));
    106     }
    107 }
    108