AppearAnimationUtils.java revision 5673353559453ecb57fc767b4e7500dd46e44079
115a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi/* 25673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggi * Copyright (C) 2015 The Android Open Source Project 315a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * 415a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * Licensed under the Apache License, Version 2.0 (the "License"); 515a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * you may not use this file except in compliance with the License. 615a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * You may obtain a copy of the License at 715a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * 815a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * http://www.apache.org/licenses/LICENSE-2.0 915a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * 1015a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * Unless required by applicable law or agreed to in writing, software 1115a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * distributed under the License is distributed on an "AS IS" BASIS, 1215a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1315a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * See the License for the specific language governing permissions and 1415a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * limitations under the License 1515a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi */ 1615a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi 175673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggipackage com.android.settingslib.animation; 1815a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi 1915a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggiimport android.content.Context; 2015a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggiimport android.view.View; 2115a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggiimport android.view.animation.AnimationUtils; 2215a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggiimport android.view.animation.Interpolator; 2315a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi 245673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggiimport com.android.settingslib.R; 255673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggi 2615a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi/** 2715a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * A class to make nice appear transitions for views in a tabular layout. 2815a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi */ 293018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinekpublic class AppearAnimationUtils implements AppearAnimationCreator<View> { 3015a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi 3198f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi public static final long DEFAULT_APPEAR_DURATION = 220; 3215a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi 3398f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi private final Interpolator mInterpolator; 3415a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi private final float mStartTranslation; 353018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek private final AppearAnimationProperties mProperties = new AppearAnimationProperties(); 36f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek protected final float mDelayScale; 3798f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi private final long mDuration; 385673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggi protected RowTranslationScaler mRowTranslationScaler; 39f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek protected boolean mAppearing; 4015a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi 4115a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi public AppearAnimationUtils(Context ctx) { 4298f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi this(ctx, DEFAULT_APPEAR_DURATION, 4376a1623afc170a13923b68f3256057d8adeb7937Jorim Jaggi 1.0f, 1.0f, 4498f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi AnimationUtils.loadInterpolator(ctx, android.R.interpolator.linear_out_slow_in)); 453018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 463018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek 4798f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi public AppearAnimationUtils(Context ctx, long duration, float translationScaleFactor, 4898f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi float delayScaleFactor, Interpolator interpolator) { 4998f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi mInterpolator = interpolator; 503018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek mStartTranslation = ctx.getResources().getDimensionPixelOffset( 513018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek R.dimen.appear_y_translation_start) * translationScaleFactor; 523018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek mDelayScale = delayScaleFactor; 5398f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi mDuration = duration; 54f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek mAppearing = true; 5515a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi } 5615a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi 575673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggi public void startAnimation2d(View[][] objects, final Runnable finishListener) { 585673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggi startAnimation2d(objects, finishListener, this); 593018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 603018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek 61f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek public void startAnimation(View[] objects, final Runnable finishListener) { 62f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek startAnimation(objects, finishListener, this); 6398f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi } 6498f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi 655673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggi public <T> void startAnimation2d(T[][] objects, final Runnable finishListener, 663018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek AppearAnimationCreator<T> creator) { 673018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek AppearAnimationProperties properties = getDelays(objects); 683018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek startAnimations(properties, objects, finishListener, creator); 693018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 703018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek 71f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek public <T> void startAnimation(T[] objects, final Runnable finishListener, 7298f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi AppearAnimationCreator<T> creator) { 7398f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi AppearAnimationProperties properties = getDelays(objects); 7498f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi startAnimations(properties, objects, finishListener, creator); 7598f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi } 7698f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi 7798f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi private <T> void startAnimations(AppearAnimationProperties properties, T[] objects, 7898f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi final Runnable finishListener, AppearAnimationCreator<T> creator) { 7998f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi if (properties.maxDelayRowIndex == -1 || properties.maxDelayColIndex == -1) { 8098f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi finishListener.run(); 8198f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi return; 8298f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi } 8398f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi for (int row = 0; row < properties.delays.length; row++) { 8498f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi long[] columns = properties.delays[row]; 8598f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi long delay = columns[0]; 8698f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi Runnable endRunnable = null; 8798f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi if (properties.maxDelayRowIndex == row && properties.maxDelayColIndex == 0) { 8898f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi endRunnable = finishListener; 8998f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi } 905673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggi float translationScale = mRowTranslationScaler != null 915673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggi ? mRowTranslationScaler.getRowTranslationScale(row, properties.delays.length) 925673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggi : 1f; 935673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggi float translation = translationScale * mStartTranslation; 9498f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi creator.createAnimation(objects[row], delay, mDuration, 955673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggi mAppearing ? translation : -translation, 965673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggi mAppearing, mInterpolator, endRunnable); 9798f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi } 9898f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi } 9998f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi 1003018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek private <T> void startAnimations(AppearAnimationProperties properties, T[][] objects, 10198f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi final Runnable finishListener, AppearAnimationCreator<T> creator) { 1023018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek if (properties.maxDelayRowIndex == -1 || properties.maxDelayColIndex == -1) { 1033018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek finishListener.run(); 1043018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek return; 1053018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 1063018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek for (int row = 0; row < properties.delays.length; row++) { 1073018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek long[] columns = properties.delays[row]; 1085673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggi float translationScale = mRowTranslationScaler != null 1095673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggi ? mRowTranslationScaler.getRowTranslationScale(row, properties.delays.length) 1105673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggi : 1f; 1115673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggi float translation = translationScale * mStartTranslation; 11215a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi for (int col = 0; col < columns.length; col++) { 1133018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek long delay = columns[col]; 1143018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek Runnable endRunnable = null; 1153018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek if (properties.maxDelayRowIndex == row && properties.maxDelayColIndex == col) { 1163018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek endRunnable = finishListener; 11715a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi } 11898f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi creator.createAnimation(objects[row][col], delay, mDuration, 119f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek mAppearing ? translation : -translation, 120f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek mAppearing, mInterpolator, endRunnable); 12115a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi } 12215a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi } 12398f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi } 1243018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek 12598f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi private <T> AppearAnimationProperties getDelays(T[] items) { 12698f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi long maxDelay = -1; 12798f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi mProperties.maxDelayColIndex = -1; 12898f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi mProperties.maxDelayRowIndex = -1; 12998f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi mProperties.delays = new long[items.length][]; 13098f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi for (int row = 0; row < items.length; row++) { 13198f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi mProperties.delays[row] = new long[1]; 13298f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi long delay = calculateDelay(row, 0); 13398f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi mProperties.delays[row][0] = delay; 13498f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi if (items[row] != null && delay > maxDelay) { 13598f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi maxDelay = delay; 13698f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi mProperties.maxDelayColIndex = 0; 13798f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi mProperties.maxDelayRowIndex = row; 13898f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi } 13998f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi } 14098f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi return mProperties; 14115a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi } 14215a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi 1433018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek private <T> AppearAnimationProperties getDelays(T[][] items) { 14498f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi long maxDelay = -1; 1453018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek mProperties.maxDelayColIndex = -1; 1463018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek mProperties.maxDelayRowIndex = -1; 1473018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek mProperties.delays = new long[items.length][]; 1483018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek for (int row = 0; row < items.length; row++) { 1493018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek T[] columns = items[row]; 1503018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek mProperties.delays[row] = new long[columns.length]; 1513018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek for (int col = 0; col < columns.length; col++) { 1523018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek long delay = calculateDelay(row, col); 1533018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek mProperties.delays[row][col] = delay; 1543018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek if (items[row][col] != null && delay > maxDelay) { 1553018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek maxDelay = delay; 1563018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek mProperties.maxDelayColIndex = col; 1573018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek mProperties.maxDelayRowIndex = row; 1583018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 1593018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 16015a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi } 1613018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek return mProperties; 16215a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi } 16315a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi 164f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek protected long calculateDelay(int row, int col) { 1653018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek return (long) ((row * 40 + col * (Math.pow(row, 0.4) + 0.4) * 20) * mDelayScale); 16615a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi } 16715a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi 1683018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek public Interpolator getInterpolator() { 16998f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi return mInterpolator; 17015a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi } 17115a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi 17215a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi public float getStartTranslation() { 17315a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi return mStartTranslation; 17415a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi } 1753018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek 1763018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek @Override 177f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek public void createAnimation(View view, long delay, long duration, float translationY, 178f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek boolean appearing, Interpolator interpolator, Runnable endRunnable) { 1793018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek if (view != null) { 180f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek view.setAlpha(appearing ? 0f : 1.0f); 181f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek view.setTranslationY(appearing ? translationY : 0); 1823018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek view.animate() 183f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek .alpha(appearing ? 1f : 0f) 184f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek .translationY(appearing ? 0 : translationY) 1853018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek .setInterpolator(interpolator) 1863018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek .setDuration(duration) 1873018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek .setStartDelay(delay); 1883018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek if (view.hasOverlappingRendering()) { 1893018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek view.animate().withLayer(); 1903018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 1913018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek if (endRunnable != null) { 1923018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek view.animate().withEndAction(endRunnable); 1933018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 1943018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 1953018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 1963018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek 1973018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek public class AppearAnimationProperties { 1983018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek public long[][] delays; 1993018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek public int maxDelayRowIndex; 2003018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek public int maxDelayColIndex; 2013018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 2025673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggi 2035673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggi public interface RowTranslationScaler { 2045673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggi float getRowTranslationScale(int row, int numRows); 2055673353559453ecb57fc767b4e7500dd46e44079Jorim Jaggi } 20615a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi} 207