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