Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
AnimateCounter provides ability to animate the counting of numbers using the builtin Android Interpolator animation functionality.
/*
* Copyright (C) 2015 Hooked On Play
*
* 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.hookedonplay.androidbycode.countitanimator;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.animation.Interpolator;
import android.widget.TextView;
/**
* AnimateCounter provides ability to animate the changing of numbers using the builtin
* Android Interpolator animation functionality.
*
*/
public class AnimateCounter {
/**
* TextView to be animated
*/
private TextView mView;
/**
* Duration of animation
*/
private long mDuration;
/**
* Initial value to start animation
*/
private float mStartValue;
/**
* End value to finish animation
*/
private float mEndValue;
/**
* Decimal precision for floating point values
*/
private int mPrecision;
/**
* Interpolator functionality to apply to animation
*/
private Interpolator mInterpolator;
private ValueAnimator mValueAnimator;
/**
* Provides optional callback functionality on completion of animation
*/
private AnimateCounterListener mListener;
/**
* Call to execute the animation
*/
public void execute(){
mValueAnimator = ValueAnimator.ofFloat(mStartValue, mEndValue);
mValueAnimator.setDuration(mDuration);
mValueAnimator.setInterpolator(mInterpolator);
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float current = Float.valueOf(valueAnimator.getAnimatedValue().toString());
mView.setText(String.format("%." + mPrecision + "f", current));
}
});
mValueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (mListener != null) {
mListener.onAnimateCounterEnd();
}
}
});
mValueAnimator.start();
}
public static class Builder {
private long mDuration = 2000;
private float mStartValue = 0;
private float mEndValue = 10;
private int mPrecision = 0;
private Interpolator mInterpolator = null;
private TextView mView;
public Builder(@NonNull TextView view) {
if (view == null) {
throw new IllegalArgumentException("View can not be null");
}
mView = view;
}
/**
* Set the start and end integers to be animated
*
* @param start initial value
* @param end final value
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setCount(final int start, final int end) {
if (start == end) {
throw new IllegalArgumentException("Count start and end must be different");
}
mStartValue = start;
mEndValue = end;
mPrecision = 0;
return this;
}
/**
* Set the start and end floating point numbers to be animated
*
* @param start initial value
* @param end final value
* @param precision number of decimal places to use
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setCount(final float start, final float end, final int precision) {
if (Math.abs(start - end) < 0.001) {
throw new IllegalArgumentException("Count start and end must be different");
}
if (precision < 0) {
throw new IllegalArgumentException("Precision can't be negative");
}
mStartValue = start;
mEndValue = end;
mPrecision = precision;
return this;
}
/**
* Set the duration of the animation from start to end
*
* @param duration total duration of animation in ms
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setDuration(long duration) {
if (duration <= 0) {
throw new IllegalArgumentException("Duration must be positive value");
}
mDuration = duration;
return this;
}
/**
* Set the interpolator to be used with the animation
*
* @param interpolator Optional interpolator to set
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setInterpolator(@Nullable Interpolator interpolator) {
mInterpolator = interpolator;
return this;
}
/**
* Creates a {@link AnimateCounter} with the arguments supplied to this builder. It does not
* {@link AnimateCounter#execute()} the AnimationCounter.
* Use {@link #execute()} to start the animation
*/
public AnimateCounter build() {
return new AnimateCounter(this);
}
}
private AnimateCounter(Builder builder) {
mView = builder.mView;
mDuration = builder.mDuration;
mStartValue = builder.mStartValue;
mEndValue = builder.mEndValue;
mPrecision = builder.mPrecision;
mInterpolator = builder.mInterpolator;
}
/**
* Stop the current animation
*/
public void stop() {
if (mValueAnimator.isRunning()) {
mValueAnimator.cancel();
}
}
/**
* Set a listener to get notification of completion of animation
*
* @param listener AnimationCounterListener to be used for callbacks
*/
public void setAnimateCounterListener(AnimateCounterListener listener) {
mListener = listener;
}
/**
* Callback interface for notification of animation end
*/
public interface AnimateCounterListener {
void onAnimateCounterEnd();
}
}
@Josef-Friedrich
Copy link

I had to change

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

into

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment