package com.github.andkulikov.materialin; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.content.res.Resources; import android.os.Build; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.ViewPropertyAnimator; import android.view.ViewTreeObserver; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; /** * Created by Andrey Kulikov on 07.05.15. */ public class MaterialIn { public static final String MATERIAL_IN_BLOCK = "materialInBlock"; public static final String MATERIAL_IN_BLOCK_WITHOUT_SLIDE = "materialInNoSlide"; public static void animate(final View view) { animate(view, Gravity.BOTTOM, Gravity.BOTTOM); } public static void animate(final View view, final int delayDirection, final int slideDirection) { if (view != null) { view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { view.getViewTreeObserver().removeOnPreDrawListener(this); initAnimation(view, 0, 0, convertGravity(view, delayDirection), convertGravity(view, slideDirection)); return true; } }); view.invalidate(); } } private static int convertGravity(View view, int gravity) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { boolean isRtl = view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; if (gravity == Gravity.START) { gravity = isRtl ? Gravity.RIGHT : Gravity.LEFT; } else if (gravity == Gravity.END) { gravity = isRtl ? Gravity.LEFT : Gravity.RIGHT; } } return gravity; } private static void initAnimation(View view, int offsetX, int offsetY, int delayDir, int slideDir) { if (offsetX < 0) { offsetX = 0; } if (offsetY < 0) { offsetY = 0; } if (view instanceof ViewGroup && ((ViewGroup) view).getChildCount() > 0 && !MATERIAL_IN_BLOCK.equals(view.getTag()) && !MATERIAL_IN_BLOCK_WITHOUT_SLIDE.equals(view.getTag())) { ViewGroup viewGroup = (ViewGroup) view; int viewHeight = viewGroup.getHeight(); for (int i = 0; i < viewGroup.getChildCount(); i++) { View child = viewGroup.getChildAt(i); int nextOffsetX = offsetX + ((delayDir == Gravity.RIGHT) ? child.getLeft() : (delayDir == Gravity.LEFT ? viewHeight - child.getRight() : 0)); int nextOffsetY = offsetY + ((delayDir == Gravity.BOTTOM) ? child.getTop() : (delayDir == Gravity.TOP ? viewHeight - child.getBottom() : 0)); initAnimation(child, nextOffsetX, nextOffsetY, delayDir, slideDir); } } else { final Resources res = view.getResources(); int slideTranslation = res.getDimensionPixelSize(R.dimen.material_in_anim_slide_offset); if (MATERIAL_IN_BLOCK_WITHOUT_SLIDE.equals(view.getTag())) { slideTranslation = 0; } int multY = 0; if (slideDir == Gravity.TOP) { multY = 1; } else if (slideDir == Gravity.BOTTOM) { multY = -1; } int multX = 0; if (slideDir == Gravity.LEFT) { multX = 1; } else if (slideDir == Gravity.RIGHT) { multX = -1; } int delayOffset = delayDir == Gravity.TOP || delayDir == Gravity.BOTTOM ? offsetY : offsetX; float delayDenominator = res.getDimension(R.dimen.material_in_delay_denominator); long delay = (long) (delayOffset / delayDenominator); startAnimators(view, slideTranslation * multX, slideTranslation * multY, delay); } } public static void startAnimators(final View view, int startOffsetX, int startOffsetY, long delay) { if (view.getVisibility() == View.VISIBLE && view.getAlpha() != 0f) { view.clearAnimation(); view.animate().cancel(); final Resources res = view.getResources(); final float endAlpha = view.getAlpha(); final float endTranslateX = view.getTranslationX(); final float endTranslateY = view.getTranslationY(); view.setAlpha(0); final Animator fade = ObjectAnimator.ofFloat(view, View.ALPHA, endAlpha); fade.setDuration(res.getInteger(R.integer.material_in_fade_anim_duration)); fade.setInterpolator(new AccelerateInterpolator()); fade.setStartDelay(delay); fade.start(); ViewPropertyAnimator slide = view.animate(); if (startOffsetY != 0) { view.setTranslationY(startOffsetY); slide.translationY(endTranslateY); } else { view.setTranslationX(startOffsetX); slide.translationX(endTranslateX); } slide.setInterpolator(new DecelerateInterpolator(2)); slide.setDuration(res.getInteger(R.integer.material_in_slide_anim_duration)); slide.setStartDelay(delay); slide.setListener(new AnimatorListenerAdapter() { @Override public void onAnimationCancel(Animator animation) { if (fade.isStarted()) { fade.cancel(); } view.setAlpha(endAlpha); view.setTranslationX(endTranslateX); view.setTranslationY(endTranslateY); } }); slide.start(); } } }