您的位置:首页 > 大数据 > 人工智能

安卓自定义View——(一:RaiseNumberAnimTextView 带数字增长动画的TextView)

2016-11-14 14:56 531 查看

前言

某些app上,新进入一个Activity的时候,上面的一个关键性数字(比如金额)会以一个数字不断变大的动画来显示。刚开始的时候,想到的一个方案是:使用Thead+Handler,给定一个动画总时长与刷新间隔时长,根据公式(数字从0开始,每次增长值为数组除以动画执行次数,动画执行次数等于动画总时长除以刷新间隔时长):

// addValue 每次刷新时数值增加多少;number 最终要显示的数字
// alltime 动画执行总时长;gaptime 动画刷新时间间隔
addValue=number/(alltime/gaptime);


每隔一段时间重新设置TextView的字符串为增加后的值,直到动画结束显示最终结果。

其实对安卓动画有一定了解的应该都知道ValueAnimator这个类,我们可以使用它来很好的实现所要的效果,而不需要我们自己来生硬的控制隔多久就增加多少刷新显示。根据ValueAnimator的属性方法以及实际需要,我们封装一个自定义View来实现我们的需求:

能自定义设置动画持续时长。

能设置int型数字或float型数字。

能控制动画速率,如匀速增加、加速、减速、先加速后减速等。

能监听到动画正常的执行结束,调用后续方法。

跟随界面的生命周期,相应的执行动画的结束、暂停、继续等操作。

RaiseNumberAnimTextView代码

根据暂时的需求,RaiseNumberAnimTextView的代码如下所示,继承自TextView,所以它拥有TextView的所有属性以及方法,其他部分的介绍见注释:

/**
* API不能低于19。
* setDuration方法设置动画执行时长
* setNumberWithAnim方法调用时将会以递增动画显示数字出来
* setAnimEndListener方法设置监听动画正常执行结束
* setAnimInterpolator方法设置动画速率
* 在该View的Activity或Fragment的onDestroy方法中调用clearAnimator方法,onPause调用onPause,onResume调用onResume。
*/
public class RaiseNumberAnimTextView extends TextView {
private long mDuration = 1000; // 动画持续时间 ms,默认1s

private ValueAnimator animator;

private TimeInterpolator mTimeInterpolator = new LinearInterpolator(); // 动画速率

private AnimEndListener mEndListener; // 动画正常结束监听事件

public RaiseNumberAnimTextView(Context context) {
super(context);
}

public RaiseNumberAnimTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}

public RaiseNumberAnimTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

/**
* 设置动画持续时间,默认为1s。需要在setNumberWithAnim之前设置才有效
* @param duration
*/
public void setDuration(long duration) {
if (duration > 0) {
mDuration = duration;
}
}

/**
* 设置动画速率,默认为LinearInterpolator。需要在setNumberWithAnim之前设置才有效
* @param timeInterpolator
*/
public void setAnimInterpolator(TimeInterpolator timeInterpolator) {
mTimeInterpolator = timeInterpolator;
}

/**
* 设置要显示的float数字,带动画显示
* @param number
*/
public void setNumberWithAnim(float number) {
clearAnimator();

// 设置动画,float值的起始值
animator = ValueAnimator.ofFloat(0.0f, number);

startAnimator();
}

/**
* 设置要显示的int数字,带动画显示。
* @param number
*/
public void setNumberWithAnim(int number) {
clearAnimator();

// 设置动画,int值的起始值
animator = ValueAnimator.ofInt(0, number);

startAnimator();
}

// 清除动画
public void clearAnimator() {
if (null != animator) {
if (animator.isRunning()) {
animator.removeAllListeners();
animator.removeAllUpdateListeners();
animator.cancel();
}
animator = null;
}
}

// 暂停动画
public void onPause() {
if (null != animator && animator.isRunning()) {
animator.pause(); // API 不低于19
}
}

// 继续执行动画
public void onResume() {
if (null != animator && animator.isRunning()) {
animator.resume();
}
}

// 设置时常与过程处理,启动动画
private void startAnimator() {
if (null != animator) {
animator.setDuration(mDuration);

animator.setInterpolator(mTimeInterpolator);

// 动画过程中获取当前值,显示
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
setText(valueAnimator.getAnimatedValue().toString());
}
});
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}

@Override
public void onAnimationEnd(Animator animator) {
if (null != mEndListener) { // 动画不是中途取消,而是正常结束
mEndListener.onAnimFinish();
}
}

@Override
public void onAnimationCancel(Animator animator) {
}

@Override
public void onAnimationRepeat(Animator animator) {
}
});
animator.start();
}
}

public void setAnimEndListener(AnimEndListener listener) {
mEndListener = listener;
}

// 动画显示数字的结束监听,当动画结束显示正确的数字时,可能需要做些处理
public interface AnimEndListener {
void onAnimFinish();
}
}


需要注意的有两点:

1. 在界面的onDestroy方法中调用clearAnimator方法,关闭该View的动画,释放资源。测试发现,界面被关掉后,该View的动画与动画结束监听还在执行。

2. 在界面的onPause调用该View的onPause,onResume调用该View的onResume。但要注意,ValueAnimator的pause()方法要求api最低版本不能低于19。低版本中则需要自己去实现动画的暂停与继续效果。另外这里也说一下为什么要加这个动画的暂停与继续,假如进入界面显示这个数字,动画执行完之后我们要弹一个Toast或者弹出一个对话框,那么我们肯定不希望当我们进入了下一个界面的时候,动画才结束这个时候做出那些操作。如果没有这些顾虑的话,可以不做这个步骤。

测试验证

使用三个RaiseNumberAnimTextView来测试,第一个和第二个均设置显示1000000,且动画时长均为5s,第一个加速显示,第二个减速显示,且第一个添加动画正常结束的监听。第三个则使用默认的速率与动画时长,显示123456.78。且在执行动画时切换界面测试动画的暂停与继续。测试代码如下(onResume、onPause、onDestroy等方法代码省略,记得要加上):

tvRaisenumber1.setAnimEndListener(new RaiseNumberAnimTextView.AnimEndListener() {
@Override
public void onAnimFinish() {
ToastUtils.showToast("第一个数字的动画执行完了");
}
});
// 测试更改值会不会异常
tvRaisenumber1.setDuration(1000 * 15);
tvRaisenumber1.setNumberWithAnim(123456.95f);
tvRaisenumber1.setDuration(1000 * 5);
tvRaisenumber1.setAnimInterpolator(new AccelerateInterpolator());
tvRaisenumber1.setNumberWithAnim(1000000);

tvRaisenumber2.setDuration(1000 * 5);
tvRaisenumber2.setAnimInterpolator(new DecelerateInterpolator());
tvRaisenumber2.setNumberWithAnim(1000000);

tvRaisenumber3.setNumberWithAnim(123456.78f);


经测试,运行正常。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 动画
相关文章推荐