Skip to content

Instantly share code, notes, and snippets.

@brucetoo
Created July 21, 2017 03:47
Show Gist options
  • Save brucetoo/be1f09a8bd34938cd6b23eadb9ede6cd to your computer and use it in GitHub Desktop.
Save brucetoo/be1f09a8bd34938cd6b23eadb9ede6cd to your computer and use it in GitHub Desktop.
ViewAnimator easier
package com.brucetoo.expandrecyclerview.animator;
import android.animation.Animator;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.support.annotation.IntRange;
import android.support.v4.view.ViewCompat;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Bruce Too
* On 12/01/2017.
* At 14:22
*/
public class AnimatorBuilder {
private final ViewAnimator mViewAnimator;
private final View[] mViews;
private final List<Animator> mAnimatorList = new ArrayList<>();
private boolean mWaitForSize;
private boolean mNextValueWillBeDp = false;
/**
* Init a new Animation builder with changeable views
*
* @param viewAnimator the view animator
* @param views the animated views
*/
public AnimatorBuilder(ViewAnimator viewAnimator, View... views) {
this.mViewAnimator = viewAnimator;
this.mViews = views;
}
/**
* Make next value be dp in animator builder.
*
* @return the animator builder
*/
public AnimatorBuilder dp() {
mNextValueWillBeDp = true;
return this;
}
/**
* Add a animator into {@link #mAnimatorList}
*
* @param animator the animator
* @return the animator builder
*/
protected AnimatorBuilder add(Animator animator) {
this.mAnimatorList.add(animator);
return this;
}
/**
* To dp float.
*
* @param px the px
* @return the float
*/
protected float toDp(final float px) {
return px / mViews[0].getContext().getResources().getDisplayMetrics().density;
}
/**
* To px float.
*
* @param dp the dp
* @return the float
*/
protected float toPx(final float dp) {
return dp * mViews[0].getContext().getResources().getDisplayMetrics().density;
}
/**
* Get values float [ ].
*
* @param values the values
* @return the float [ ]
*/
protected float[] getValues(float... values) {
if (!mNextValueWillBeDp) {
return values;
}
float[] pxValues = new float[values.length];
for (int i = 0; i < values.length; ++i) {
pxValues[i] = toPx(values[i]);
}
return pxValues;
}
/**
* Property animator builder.
*
* @param propertyName the property name
* @param values the values
* @return the animator builder
*/
public AnimatorBuilder property(String propertyName, float... values) {
for (View view : mViews) {
this.mAnimatorList.add(ObjectAnimator.ofFloat(view, propertyName, getValues(values)));
}
return this;
}
/**
* Translation y animator builder.
*
* @param y the y
* @return the animator builder
*/
public AnimatorBuilder translationY(float... y) {
return property("translationY", y);
}
/**
* Translation x animator builder.
*
* @param x the x
* @return the animator builder
*/
public AnimatorBuilder translationX(float... x) {
return property("translationX", x);
}
/**
* Alpha animator builder.
*
* @param alpha the alpha
* @return the animator builder
*/
public AnimatorBuilder alpha(float... alpha) {
return property("alpha", alpha);
}
/**
* Scale x animator builder.
*
* @param scaleX the scale x
* @return the animator builder
*/
public AnimatorBuilder scaleX(float... scaleX) {
return property("scaleX", scaleX);
}
/**
* Scale y animator builder.
*
* @param scaleY the scale y
* @return the animator builder
*/
public AnimatorBuilder scaleY(float... scaleY) {
return property("scaleY", scaleY);
}
/**
* Scale animator builder.
*
* @param scale the scale
* @return the animator builder
*/
public AnimatorBuilder scale(float... scale) {
scaleX(scale);
scaleY(scale);
return this;
}
/**
* Pivot x animator builder.
*
* @param pivotX the pivot x
* @return the animator builder
*/
public AnimatorBuilder pivotX(float pivotX) {
for (View view : mViews) {
ViewCompat.setPivotX(view, pivotX);
}
return this;
}
/**
* Pivot y animator builder.
*
* @param pivotY the pivot y
* @return the animator builder
*/
public AnimatorBuilder pivotY(float pivotY) {
for (View view : mViews) {
ViewCompat.setPivotY(view, pivotY);
}
return this;
}
public AnimatorBuilder rotationX(float... rotationX) {
return property("rotationX", rotationX);
}
/**
* Rotation y animator builder.
*
* @param rotationY the rotation y
* @return the animator builder
*/
public AnimatorBuilder rotationY(float... rotationY) {
return property("rotationY", rotationY);
}
/**
* Rotation animator builder.
*
* @param rotation the rotation
* @return the animator builder
*/
public AnimatorBuilder rotation(float... rotation) {
return property("rotation", rotation);
}
/**
* Background color animator builder.
*
* @param colors the colors
* @return the animator builder
*/
public AnimatorBuilder backgroundColor(int... colors) {
for (View view : mViews) {
ObjectAnimator objectAnimator = ObjectAnimator.ofInt(view, "backgroundColor", colors);
objectAnimator.setEvaluator(new ArgbEvaluator());
this.mAnimatorList.add(objectAnimator);
}
return this;
}
/**
* Text color animator builder.
*
* @param colors the colors
* @return the animator builder
*/
public AnimatorBuilder textColor(int... colors) {
for (View view : mViews) {
if (view instanceof TextView) {
ObjectAnimator objectAnimator = ObjectAnimator.ofInt(view, "textColor", colors);
objectAnimator.setEvaluator(new ArgbEvaluator());
this.mAnimatorList.add(objectAnimator);
}
}
return this;
}
/**
* Custom animator builder.
*
* @param update the onUpdate
* @param values the values
* @return the animator builder
*/
public AnimatorBuilder custom(final AnimatorListener.Update update, float... values) {
for (final View view : mViews) {
ValueAnimator valueAnimator = ValueAnimator.ofFloat(getValues(values));
if (update != null)
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//noinspection unchecked
update.onUpdate(view, (Float) animation.getAnimatedValue());
}
});
add(valueAnimator);
}
return this;
}
/**
* Height animator builder.
*
* @param height the height
* @return the animator builder
*/
public AnimatorBuilder height(float... height) {
return custom(new AnimatorListener.Update() {
@Override
public void onUpdate(View view, float value) {
view.getLayoutParams().height = (int) value;
view.requestLayout();
}
}, height);
}
/**
* Width animator builder.
*
* @param width the width
* @return the animator builder
*/
public AnimatorBuilder width(float... width) {
return custom(new AnimatorListener.Update() {
@Override
public void onUpdate(View view, float value) {
view.getLayoutParams().width = (int) value;
view.requestLayout();
}
}, width);
}
/**
* Wait for height animator builder.
*
* @return the animator builder
*/
public AnimatorBuilder waitForSize() {
mWaitForSize = true;
return this;
}
/**
* Get pending animators list.
*
* @return the list
*/
protected List<Animator> getPendingAnimators() {
return mAnimatorList;
}
/**
* And animate animator builder.
*
* @param views the mViews
* @return the animator builder
*/
public AnimatorBuilder andAnimate(View... views) {
return mViewAnimator.addAnimatorBuilder(views);
}
/**
* Then animate animator builder.
*
* @param views the mViews
* @return the animator builder
*/
public AnimatorBuilder thenAnimate(View... views) {
return mViewAnimator.thenAnimate(views);
}
/**
* Duration view animator.
*
* @param duration the duration
* @return the animator builder
*/
public AnimatorBuilder duration(long duration) {
mViewAnimator.duration(duration);
return this;
}
/**
* Start delay view animator.
*
* @param startDelay the start delay
* @return the animator builder
*/
public AnimatorBuilder startDelay(long startDelay) {
mViewAnimator.startDelay(startDelay);
return this;
}
/**
* Repeat count of animator.
*
* @param repeatCount the repeat count
* @return the animator builder
*/
public AnimatorBuilder repeatCount(@IntRange(from = -1) int repeatCount) {
mViewAnimator.repeatCount(repeatCount);
return this;
}
/**
* Repeat mode view animator.
*
* @param repeatMode the repeat mode
* @return the animator builder
*/
public AnimatorBuilder repeatMode(@ViewAnimator.RepeatMode int repeatMode) {
mViewAnimator.repeatMode(repeatMode);
return this;
}
/**
* On start view animator.
*
* @param startListener the start listener
* @return the animator builder
*/
public AnimatorBuilder onStart(AnimatorListener.Start startListener) {
mViewAnimator.onStart(startListener);
return this;
}
/**
* On stop view animator.
*
* @param endListener the stop listener
* @return the animator builder
*/
public AnimatorBuilder onEnd(AnimatorListener.End endListener) {
mViewAnimator.onEnd(endListener);
return this;
}
/**
* Interpolator for all view animators.
*
* @param interpolator the interpolator
* @return the animator builder
*/
public AnimatorBuilder interpolator(Interpolator interpolator) {
mViewAnimator.interpolator(interpolator);
return this;
}
/**
* Set accelerate interpolator
* @return ViewAnimator
*/
public ViewAnimator accelerate() {
return mViewAnimator.interpolator(new AccelerateInterpolator());
}
/**
* Set decelerate interpolator
* @return ViewAnimator
*/
public ViewAnimator decelerate() {
return mViewAnimator.interpolator(new DecelerateInterpolator());
}
/**
* Start current animator
*/
public ViewAnimator start() {
mViewAnimator.start();
return mViewAnimator;
}
/**
* Get mViews view [ ].
*
* @return the view [ ]
*/
public View[] getViews() {
return mViews;
}
/**
* Wait the view be inflated
*
* @return the boolean
*/
public boolean isWaitForSize() {
return mWaitForSize;
}
}
package com.brucetoo.expandrecyclerview.animator;
import android.view.View;
/**
* Created by Bruce Too
* On 12/01/2017.
* At 14:23
*/
public class AnimatorListener {
private AnimatorListener(){}
public interface Start{
void onStart();
}
public interface End {
void onEnd();
}
public interface Update<V extends View>{
void onUpdate(V view, float value);
}
}
package com.brucetoo.expandrecyclerview.animator;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.support.annotation.IntDef;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.v4.view.ViewCompat;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.Interpolator;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Bruce Too
* On 12/01/2017.
* At 14:20
*/
public class ViewAnimator {
private static final long DEFAULT_DURATION = 3000;
private List<AnimatorBuilder> mAnimatorBuilderList = new ArrayList<>();
private long mAnimatorDuration = DEFAULT_DURATION;
private long mAnimatorStartDelay = 0;
private Interpolator mAnimatorInterpolator = null;
private int mAnimatorRepeatCount = 0;
private int mAnimatorRepeatMode = ValueAnimator.RESTART;
private AnimatorSet mAnimatorSet;
private View mWaitForThisViewSize = null;
private AnimatorListener.Start mStartListener;
private AnimatorListener.End mEndListener;
private ViewAnimator mPreviousViewAnimator = null;
private ViewAnimator mNextViewAnimator = null;
private View[] mViews;
public ViewAnimator() {
}
public ViewAnimator(View... view) {
this.mViews = view;
}
@IntDef(value = {ValueAnimator.RESTART, ValueAnimator.REVERSE})
@Retention(RetentionPolicy.SOURCE)
public @interface RepeatMode {
}
/* ----- Set Properties ------*/
public static ViewAnimator putOn(View... view) {
return new ViewAnimator(view);
}
public ViewAnimator andPutOn(View... view) {
this.mViews = view;
return this;
}
public ViewAnimator alpha(float alpha) {
if (mViews != null) {
for (View view : mViews) {
ViewCompat.setAlpha(view, alpha);
}
}
return this;
}
public ViewAnimator scaleX(float scale) {
if (mViews != null) {
for (View view : mViews) {
ViewCompat.setScaleX(view, scale);
}
}
return this;
}
public ViewAnimator scaleY(float scale) {
if (mViews != null) {
for (View view : mViews) {
ViewCompat.setScaleY(view, scale);
}
}
return this;
}
public ViewAnimator scale(float scale) {
if (mViews != null) {
for (View view : mViews) {
ViewCompat.setScaleX(view, scale);
ViewCompat.setScaleY(view, scale);
}
}
return this;
}
public ViewAnimator translationX(float translation) {
if (mViews != null) {
for (View view : mViews) {
ViewCompat.setTranslationX(view, translation);
}
}
return this;
}
public ViewAnimator translationY(float translation) {
if (mViews != null) {
for (View view : mViews) {
ViewCompat.setTranslationY(view, translation);
}
}
return this;
}
public ViewAnimator translation(float translationX, float translationY) {
if (mViews != null) {
for (View view : mViews) {
ViewCompat.setTranslationX(view, translationX);
ViewCompat.setTranslationY(view, translationY);
}
}
return this;
}
public ViewAnimator pivotX(float percent) {
if (mViews != null) {
for (View view : mViews) {
ViewCompat.setPivotX(view, view.getWidth() * percent);
}
}
return this;
}
public ViewAnimator pivotY(float percent) {
if (mViews != null) {
for (View view : mViews) {
ViewCompat.setPivotY(view, view.getHeight() * percent);
}
}
return this;
}
public ViewAnimator visible() {
if (mViews != null) {
for (View view : mViews) {
view.setVisibility(View.VISIBLE);
}
}
return this;
}
public ViewAnimator invisible() {
if (mViews != null) {
for (View view : mViews) {
view.setVisibility(View.INVISIBLE);
}
}
return this;
}
public ViewAnimator gone() {
if (mViews != null) {
for (View view : mViews) {
view.setVisibility(View.GONE);
}
}
return this;
}
/* ----- Animator Properties ------*/
/**
* Execute animator in views be add by {@link #putOn(View...)}
*
* @return AnimatorBuilder
*/
public AnimatorBuilder animate() {
ViewAnimator viewAnimator = new ViewAnimator();
return viewAnimator.addAnimatorBuilder(mViews);
}
/**
* Execute animator in views by given now
*
* @param views views by animated
* @return AnimatorBuilder
*/
public static AnimatorBuilder animate(@NonNull View... views) {
ViewAnimator viewAnimator = new ViewAnimator();
return viewAnimator.addAnimatorBuilder(views);
}
public AnimatorBuilder thenAnimate(@NonNull View... views) {
ViewAnimator nextViewAnimator = new ViewAnimator();
this.mNextViewAnimator = nextViewAnimator;
nextViewAnimator.mPreviousViewAnimator = this;
return nextViewAnimator.addAnimatorBuilder(views);
}
public AnimatorBuilder addAnimatorBuilder(View... views) {
AnimatorBuilder animatorBuilder = new AnimatorBuilder(this, views);
mAnimatorBuilderList.add(animatorBuilder);
return animatorBuilder;
}
protected AnimatorSet createAnimatorSet() {
List<Animator> animators = new ArrayList<>();
//add all pending property animators
for (AnimatorBuilder animatorBuilder : mAnimatorBuilderList) {
List<Animator> animatorList = animatorBuilder.getPendingAnimators();
animators.addAll(animatorList);
}
//find if need wait for size
for (AnimatorBuilder animatorBuilder : mAnimatorBuilderList) {
if (animatorBuilder.isWaitForSize()) {
mWaitForThisViewSize = animatorBuilder.getViews()[0];
break;
}
}
//set repeat mode and count if had be set
for (Animator animator : animators) {
if (animator instanceof ValueAnimator) {
ValueAnimator valueAnimator = (ValueAnimator) animator;
valueAnimator.setRepeatCount(mAnimatorRepeatCount);
valueAnimator.setRepeatMode(mAnimatorRepeatMode);
}
}
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(animators);
animatorSet.setDuration(mAnimatorDuration);
animatorSet.setStartDelay(mAnimatorStartDelay);
if (mAnimatorInterpolator != null)
animatorSet.setInterpolator(mAnimatorInterpolator);
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
if (mStartListener != null) mStartListener.onStart();
}
@Override
public void onAnimationEnd(Animator animation) {
if (mEndListener != null) mEndListener.onEnd();
if (mNextViewAnimator != null) {
mNextViewAnimator.mPreviousViewAnimator = null;
mNextViewAnimator.start();
}
}
});
return animatorSet;
}
public ViewAnimator start() {
if (mPreviousViewAnimator != null) {
mPreviousViewAnimator.start();
} else {
mAnimatorSet = createAnimatorSet();
if (mWaitForThisViewSize != null) {
mWaitForThisViewSize.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
mAnimatorSet.start();
mWaitForThisViewSize.getViewTreeObserver().removeOnPreDrawListener(this);
return false;
}
});
} else {
mAnimatorSet.start();
}
}
return this;
}
public void cancel() {
if (mAnimatorSet != null) {
mAnimatorSet.cancel();
}
if (mNextViewAnimator != null) {
mNextViewAnimator.cancel();
mNextViewAnimator = null;
}
}
public ViewAnimator duration(long duration) {
this.mAnimatorDuration = duration;
return this;
}
public ViewAnimator startDelay(long startDelay) {
this.mAnimatorStartDelay = startDelay;
return this;
}
/**
* Repeat count of animation.
*
* @param repeatCount the repeat count
* @return the view animation
*/
public ViewAnimator repeatCount(@IntRange(from = -1) int repeatCount) {
this.mAnimatorRepeatCount = repeatCount;
return this;
}
/**
* Repeat mode view animation.
*
* @param repeatMode the repeat mode
* @return the view animation
*/
public ViewAnimator repeatMode(@RepeatMode int repeatMode) {
this.mAnimatorRepeatMode = repeatMode;
return this;
}
public ViewAnimator onStart(AnimatorListener.Start startListener) {
this.mStartListener = startListener;
return this;
}
public ViewAnimator onEnd(AnimatorListener.End endListener) {
this.mEndListener = endListener;
return this;
}
/**
* Interpolator view animator.
*
* @param interpolator the mAnimatorInterpolator
* @return the view animator
* @link https://github.com/cimi-chen/EaseInterpolator
*/
public ViewAnimator interpolator(Interpolator interpolator) {
this.mAnimatorInterpolator = interpolator;
return this;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment