blob: eac3ff84508fd868b8cb328b6ea663ce8244bd38 [file] [log] [blame]
Alan Viverette95888c02015-04-16 13:27:50 -07001/*
2 * Copyright (C) 2015 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 */
16package com.android.internal.transition;
17
18import com.android.internal.R;
19
20import android.animation.Animator;
21import android.animation.AnimatorSet;
22import android.animation.ObjectAnimator;
23import android.animation.TimeInterpolator;
24import android.content.Context;
25import android.content.res.TypedArray;
26import android.graphics.Rect;
27import android.transition.TransitionValues;
28import android.transition.Visibility;
29import android.util.AttributeSet;
30import android.view.View;
31import android.view.ViewGroup;
32import android.view.animation.AnimationUtils;
33
34/**
35 * EpicenterTranslate captures the {@link View#getTranslationX()} and
36 * {@link View#getTranslationY()} before and after the scene change and
37 * animates between those and the epicenter's center during a visibility
38 * transition.
39 */
40public class EpicenterTranslate extends Visibility {
41 private static final String PROPNAME_BOUNDS = "android:epicenterReveal:bounds";
42 private static final String PROPNAME_TRANSLATE_X = "android:epicenterReveal:translateX";
43 private static final String PROPNAME_TRANSLATE_Y = "android:epicenterReveal:translateY";
44 private static final String PROPNAME_TRANSLATE_Z = "android:epicenterReveal:translateZ";
45 private static final String PROPNAME_Z = "android:epicenterReveal:z";
46
47 private final TimeInterpolator mInterpolatorX;
48 private final TimeInterpolator mInterpolatorY;
49 private final TimeInterpolator mInterpolatorZ;
50
51 public EpicenterTranslate() {
52 mInterpolatorX = null;
53 mInterpolatorY = null;
54 mInterpolatorZ = null;
55 }
56
57 public EpicenterTranslate(Context context, AttributeSet attrs) {
58 super(context, attrs);
59
60 final TypedArray a = context.obtainStyledAttributes(attrs,
61 R.styleable.EpicenterTranslate, 0, 0);
62
63 final int interpolatorX = a.getResourceId(R.styleable.EpicenterTranslate_interpolatorX, 0);
64 if (interpolatorX != 0) {
65 mInterpolatorX = AnimationUtils.loadInterpolator(context, interpolatorX);
66 } else {
67 mInterpolatorX = TransitionConstants.FAST_OUT_SLOW_IN;
68 }
69
70 final int interpolatorY = a.getResourceId(R.styleable.EpicenterTranslate_interpolatorY, 0);
71 if (interpolatorY != 0) {
72 mInterpolatorY = AnimationUtils.loadInterpolator(context, interpolatorY);
73 } else {
74 mInterpolatorY = TransitionConstants.FAST_OUT_SLOW_IN;
75 }
76
77 final int interpolatorZ = a.getResourceId(R.styleable.EpicenterTranslate_interpolatorZ, 0);
78 if (interpolatorZ != 0) {
79 mInterpolatorZ = AnimationUtils.loadInterpolator(context, interpolatorZ);
80 } else {
81 mInterpolatorZ = TransitionConstants.FAST_OUT_SLOW_IN;
82 }
83
84 a.recycle();
85 }
86
87 @Override
88 public void captureStartValues(TransitionValues transitionValues) {
89 super.captureStartValues(transitionValues);
90 captureValues(transitionValues);
91 }
92
93 @Override
94 public void captureEndValues(TransitionValues transitionValues) {
95 super.captureEndValues(transitionValues);
96 captureValues(transitionValues);
97 }
98
99 private void captureValues(TransitionValues values) {
100 final View view = values.view;
101 if (view.getVisibility() == View.GONE) {
102 return;
103 }
104
105 final Rect bounds = new Rect(0, 0, view.getWidth(), view.getHeight());
106 values.values.put(PROPNAME_BOUNDS, bounds);
107 values.values.put(PROPNAME_TRANSLATE_X, view.getTranslationX());
108 values.values.put(PROPNAME_TRANSLATE_Y, view.getTranslationY());
109 values.values.put(PROPNAME_TRANSLATE_Z, view.getTranslationZ());
110 values.values.put(PROPNAME_Z, view.getZ());
111 }
112
113 @Override
114 public Animator onAppear(ViewGroup sceneRoot, View view,
115 TransitionValues startValues, TransitionValues endValues) {
116 if (endValues == null) {
117 return null;
118 }
119
120 final Rect end = (Rect) endValues.values.get(PROPNAME_BOUNDS);
121 final Rect start = getEpicenterOrCenter(end);
122 final float startX = start.centerX() - end.centerX();
123 final float startY = start.centerY() - end.centerY();
124 final float startZ = 0 - (float) endValues.values.get(PROPNAME_Z);
125
126 // Translate the view to be centered on the epicenter.
127 view.setTranslationX(startX);
128 view.setTranslationY(startY);
129 view.setTranslationZ(startZ);
130
131 final float endX = (float) endValues.values.get(PROPNAME_TRANSLATE_X);
132 final float endY = (float) endValues.values.get(PROPNAME_TRANSLATE_Y);
133 final float endZ = (float) endValues.values.get(PROPNAME_TRANSLATE_Z);
134 return createAnimator(view, startX, startY, startZ, endX, endY, endZ,
135 mInterpolatorX, mInterpolatorY, mInterpolatorZ);
136 }
137
138 @Override
139 public Animator onDisappear(ViewGroup sceneRoot, View view,
140 TransitionValues startValues, TransitionValues endValues) {
141 if (startValues == null) {
142 return null;
143 }
144
145 final Rect start = (Rect) endValues.values.get(PROPNAME_BOUNDS);
146 final Rect end = getEpicenterOrCenter(start);
147 final float endX = end.centerX() - start.centerX();
148 final float endY = end.centerY() - start.centerY();
149 final float endZ = 0 - (float) startValues.values.get(PROPNAME_Z);
150
151 final float startX = (float) endValues.values.get(PROPNAME_TRANSLATE_X);
152 final float startY = (float) endValues.values.get(PROPNAME_TRANSLATE_Y);
153 final float startZ = (float) endValues.values.get(PROPNAME_TRANSLATE_Z);
154 return createAnimator(view, startX, startY, startZ, endX, endY, endZ,
155 mInterpolatorX, mInterpolatorY, mInterpolatorZ);
156 }
157
158 private Rect getEpicenterOrCenter(Rect bestRect) {
159 final Rect epicenter = getEpicenter();
160 if (epicenter != null) {
161 return epicenter;
162 }
163
164 final int centerX = bestRect.centerX();
165 final int centerY = bestRect.centerY();
166 return new Rect(centerX, centerY, centerX, centerY);
167 }
168
169 private static Animator createAnimator(final View view, float startX, float startY,
170 float startZ, float endX, float endY, float endZ, TimeInterpolator interpolatorX,
171 TimeInterpolator interpolatorY, TimeInterpolator interpolatorZ) {
172 final ObjectAnimator animX = ObjectAnimator.ofFloat(view, View.TRANSLATION_X, startX, endX);
173 if (interpolatorX != null) {
174 animX.setInterpolator(interpolatorX);
175 }
176
177 final ObjectAnimator animY = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, startY, endY);
178 if (interpolatorY != null) {
179 animY.setInterpolator(interpolatorY);
180 }
181
182 final ObjectAnimator animZ = ObjectAnimator.ofFloat(view, View.TRANSLATION_Z, startZ, endZ);
183 if (interpolatorZ != null) {
184 animZ.setInterpolator(interpolatorZ);
185 }
186
187 final AnimatorSet animSet = new AnimatorSet();
188 animSet.playTogether(animX, animY, animZ);
189 return animSet;
190 }
191}