今天我们自定义一个TextView,它的名称叫做RiseNumberTextView,我们在平时使用支付宝的时候会发现进入资产页面的时候,资产数据会从一个数一直不停的增长直至你的真实数据然后停止。
那么这个效果是如何做到的呢?首先来看一下我们做出的效果图,然后我们一起来实现它。
这里面会用到一个核心的类:ValueAnimatr这是一个android属性动画
按照面向接口编程的好习惯,首先定义一个接口:
/** * 增长的数字接口 * */ public interface IRiseNumber { /** * 开始播放动画的方法 */ public void start(); /** * 设置小数 * * @param number * @return */ public void withNumber(float number); /** * 设置整数 * * @param number * @return */ public void withNumber(int number); /** * 设置动画播放时长 * * @param duration * @return */ public void setDuration(long duration); /** * 设置动画结束监听器 * * @param callback */ public void setOnEndListener(RiseNumberTextView.EndListener callback); }
然后自定义view------数字增长TextView,内容如下:
import android.content.Context; import android.util.AttributeSet; import android.widget.TextView; import com.bear.risenumber.R; import com.nineoldandroids.animation.ValueAnimator; import java.text.DecimalFormat; /** * 自定义RiseNumberTextView继承TextView,并实现接口RiseNumberBase * */ public class RiseNumberTextView extends TextView implements IRiseNumber { private static final int STOPPED = 0; private static final int RUNNING = 1; private int mPlayingState = STOPPED; private float number; private float fromNumber; /** * 动画播放时长 */ private long duration = 1500; /** * 1.int 2.float */ private int numberType = 2; private DecimalFormat fnum; private EndListener mEndListener = null; final static int[] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, Integer.MAX_VALUE }; /** * 构造方法 * * @param context */ public RiseNumberTextView(Context context) { super(context); } /** * 使用xml布局文件默认的被调用的构造方法 * * @param context * @param attr */ public RiseNumberTextView(Context context, AttributeSet attr) { super(context, attr); setTextColor(context.getResources().getColor(R.color.rise_number_text_color_red)); setTextSize(30); } public RiseNumberTextView(Context context, AttributeSet attr, int defStyle) { super(context, attr, defStyle); } /** * 判断动画是否正在播放 * * @return */ public boolean isRunning() { return (mPlayingState == RUNNING); } /** * 跑小数动画 */ private void runFloat() { ValueAnimator valueAnimator = ValueAnimator.ofFloat(fromNumber, number); valueAnimator.setDuration(duration); valueAnimator .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { setText(fnum.format(Float.parseFloat(valueAnimator .getAnimatedValue().toString()))); if (valueAnimator.getAnimatedFraction() >= 1) { mPlayingState = STOPPED; if (mEndListener != null) mEndListener.onEndFinish(); } } }); valueAnimator.start(); } /** * 跑整数动画 */ private void runInt() { ValueAnimator valueAnimator = ValueAnimator.ofInt((int) fromNumber, (int) number); valueAnimator.setDuration(duration); valueAnimator .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { //设置瞬时的数据值到界面上 setText(valueAnimator.getAnimatedValue().toString()); if (valueAnimator.getAnimatedFraction() >= 1) { //设置状态为停止 mPlayingState = STOPPED; if (mEndListener != null) //通知监听器,动画结束事件 mEndListener.onEndFinish(); } } }); valueAnimator.start(); } static int sizeOfInt(int x) { for (int i = 0;; i++){ if (x <= sizeTable[i]) return i + 1; } } @Override protected void onFinishInflate() { super.onFinishInflate(); fnum = new DecimalFormat("##0.00"); } /** * 开始播放动画 */ @Override public void start() { if (!isRunning()) { mPlayingState = RUNNING; if (numberType == 1) runInt(); else runFloat(); } } /** * 设置一个小数进来 */ @Override public void withNumber(float number) { this.number = number; numberType = 2; if (number > 1000) { fromNumber = number - (float) Math.pow(10, sizeOfInt((int) number) - 1); } else { fromNumber = number / 2; } } /** * 设置一个整数进来 */ @Override public void withNumber(int number) { this.number = number; numberType = 1; if (number > 1000) { fromNumber = number - (float) Math.pow(10, sizeOfInt((int) number) - 2); } else { fromNumber = number / 2; } } /** * 设置动画播放时间 */ @Override public void setDuration(long duration) { this.duration = duration; } /** * 设置动画结束监听器 */ @Override public void setOnEndListener(EndListener callback) { mEndListener = callback; } /** * 定义动画结束接口 * * */ public interface EndListener { /** * 当动画播放结束时的回调方法 */ public void onEndFinish(); } }
然后在Activity中去使用自定义的view:
import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; import com.bear.risenumber.views.RiseNumberTextView; import com.bear.risenumber.views.RiseNumberTextView.EndListener; public class MainActivity extends Activity { private RiseNumberTextView rnTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setupViews(); } private void setupViews() { // 获取到RiseNumberTextView对象 rnTextView = (RiseNumberTextView) findViewById(R.id.risenumber_textview); // 设置数据 rnTextView.withNumber(2666.50f); // 设置动画播放时间 rnTextView.setDuration(5000); // 监听动画播放结束 rnTextView.setOnEndListener(new EndListener() { @Override public void onEndFinish() { Toast.makeText(MainActivity.this, "数据增长完毕...", Toast.LENGTH_SHORT).show(); } }); Button btn = (Button) findViewById(R.id.button1); btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if(rnTextView.isRunning()){ Toast.makeText(MainActivity.this, "数字还没增长完,请稍候尝试...", Toast.LENGTH_SHORT).show(); }else{ // 开始播放动画 rnTextView.start(); } } }); } }
附上示例源码,有兴趣的可以下载导入到Eclipse中去运行以下:
Android Rise Number TextView