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