Android之增长的数字(仿支付宝资产数字)

今天我们自定义一个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


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。