Skip to content

Instantly share code, notes, and snippets.

@brianrobles204
Last active March 7, 2019 09:28
Show Gist options
  • Save brianrobles204/8b0f16a207359d0d50e340fd97182c58 to your computer and use it in GitHub Desktop.
Save brianrobles204/8b0f16a207359d0d50e340fd97182c58 to your computer and use it in GitHub Desktop.
Android animation utility class. Contains quick references to commonly used constants, as well as helper functions for material animations.
/*
* Copyright (C) 2016 Brian Carlos L. Robles
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.brianrobles204.karmamachine.util;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.TypeEvaluator;
import android.annotation.SuppressLint;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.animation.FastOutLinearInInterpolator;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.support.v4.view.animation.LinearOutSlowInInterpolator;
import android.util.Property;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.view.animation.Interpolator;
import java.util.Collection;
/**
* Created by brianrobles204 on 10/26/15.
*
* <p>Utility class for working with animations.
* This class contains public and static copies of common animation values
* and interpolator objects.
*/
public class AnimUtils {
/**
* The duration (in milliseconds) of a short animation.
*/
public static final int SHORT_DURATION = 200;
/**
* The duration (in milliseconds) of a medium-length animation.
*/
public static final int MEDIUM_DURATION = 400;
/**
* The duration (in milliseconds) of a long animation.
*/
public static final int LONG_DURATION = 500;
/**
* The duration (in milliseconds) of an extra long animation.
*/
public static final int EXTRA_LONG_DURATION = 750;
/**
* An interpolator which starts out slow but accelerates towards the end.
* The interpolator is designed for material design animations.
* This implementation uses a {@link FastOutLinearInInterpolator}.
*
* <p>This interpolator is best used with <b>removal</b> animations, because
* the speed increases as the animation ends.
*
* @see <a href="https://www.google.com/design/spec/animation/authentic-motion.html#">
* Google Design Guidelines on Authentic Motion</a>
*/
public static final Interpolator ACCELERATE_INTERPOLATOR =
new FastOutLinearInInterpolator();
/**
* An interpolator which starts out fast but decelerates towards the end.
* The interpolator is designed for material design animations.
* This implementation uses a {@link LinearOutSlowInInterpolator}
*
* <p>This interpolator is best used with <b>addition</b> animations, because
* the speed slows to a stop towards the end.
*
* @see <a href="https://www.google.com/design/spec/animation/authentic-motion.html#">
* Google Design Guidelines on Authentic Motion</a>
*/
public static final Interpolator DECELERATE_INTERPOLATOR =
new LinearOutSlowInInterpolator();
/**
* An interpolator which is tweaked to be used when objects are to be shown, hidden,
* or moved on the screen. The interpolator is designed for material design animations.
* This implementation uses a {@link FastOutSlowInInterpolator}.
*
* @see <a href="https://www.google.com/design/spec/animation/authentic-motion.html#">
* Google Design Guidelines on Authentic Motion</a>
*/
public static final Interpolator SHOW_HIDE_INTERPOLATOR =
new FastOutSlowInInterpolator();
private AnimUtils() { }
/**
* Creates and runs a slide in animation on the children of the given {@code parent}
* in a "material"-like manner similar to the demos on the
* <a href="https://www.google.com/design/spec/animation/">Google Design Guidelines
* on Animations</a>.
*
* @param parent {@link ViewGroup} whose children will be animated in.
* @param direction Direction which the animation will move to.
* @param slideDistance Magnitude of the slide.
* @param onAnimFinish {@link Runnable} to be invoked when the animation has finished.
* May be {@code null}.
*/
public static void materialAnimateChildrenIn(ViewGroup parent, int direction,
int slideDistance, Runnable onAnimFinish) {
materialAnimateChildren(parent, true, direction, slideDistance, onAnimFinish);
}
/**
* Creates and runs a slide out animation on the children of the given {@code parent}
* in a "material"-like manner similar to the demos on the
* <a href="https://www.google.com/design/spec/animation/">Google Design Guidelines
* on Animations</a>.
*
* @param parent {@link ViewGroup} whose children will be animated out.
* @param direction Direction which the animation will move towards.
* @param slideDistance Magnitude of the slide.
* @param onAnimFinish {@link Runnable} to be invoked when the animation has finished.
* May be {@code null}.
*/
public static void materialAnimateChildrenOut(ViewGroup parent, int direction,
int slideDistance, Runnable onAnimFinish) {
materialAnimateChildren(parent, false, direction, slideDistance, onAnimFinish);
}
@SuppressLint("RtlHardcoded")
private static void materialAnimateChildren(final ViewGroup parent, final boolean appear,
int direction, int slideDistance,
final Runnable onAnimFinish) {
parent.setAlpha(1);
parent.setTranslationY(0);
parent.setVisibility(View.VISIBLE);
if (parent.getChildCount() == 0) {
return;
}
int absGravity = GravityCompat.getAbsoluteGravity(direction,
ViewCompat.getLayoutDirection(parent));
boolean reverse = (direction & Gravity.TOP) == Gravity.TOP ||
(absGravity & Gravity.LEFT) == Gravity.LEFT;
int size = parent.getChildCount();
int animSize = 0;
for (int i = 0; i < size; i++) {
if (parent.getChildAt(i).getVisibility() == View.VISIBLE) animSize++;
}
boolean hasSetListener = false;
int skipCount = 0;
for (int i = 0; i < size; i++) {
View child = parent.getChildAt(i);
if (child.getVisibility() != View.VISIBLE) {
skipCount++;
continue;
}
final int index = i - skipCount;
final int animIndex = reverse ? animSize - index : index;
final float offset = AnimUtils.ACCELERATE_INTERPOLATOR
.getInterpolation((float) animIndex / animSize);
final float translation = slideDistance + (offset * animIndex * slideDistance);
final float startAlpha = appear ? 0 : 1;
final float endAlpha = appear ? 1 : 0;
final float startTrans = appear ? reverse ? -translation : translation : 0;
final float endTrans = appear ? 0 : reverse ? -translation : translation;
child.setLayerType(View.LAYER_TYPE_HARDWARE, null);
child.setAlpha(startAlpha);
if (Gravity.isHorizontal(direction)) {
child.setTranslationX(startTrans);
}
if (Gravity.isVertical(direction)) {
child.setTranslationY(startTrans);
}
ViewPropertyAnimator animator = child.animate()
.alpha(endAlpha);
if (Gravity.isHorizontal(direction)) {
animator.translationX(endTrans);
}
if (Gravity.isVertical(direction)) {
animator.translationY(endTrans);
}
if (appear) {
animator.setStartDelay(AnimUtils.LONG_DURATION/2);
} else {
animator.setStartDelay(0);
}
animator.setDuration(AnimUtils.LONG_DURATION)
.setInterpolator(!appear ? AnimUtils.ACCELERATE_INTERPOLATOR :
AnimUtils.DECELERATE_INTERPOLATOR);
if (!hasSetListener) {
hasSetListener = true;
animator.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
parent.getChildAt(0).animate().setListener(null);
if (appear) {
parent.setVisibility(View.VISIBLE);
} else {
parent.setVisibility(View.GONE);
}
if (onAnimFinish != null) onAnimFinish.run();
for (int i = 0; i < parent.getChildCount(); i++) {
View view = parent.getChildAt(i);
view.setAlpha(1);
view.setTranslationY(0);
}
}
});
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment