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

时间: 2024-10-09 23:08:41

Android之增长的数字(仿支付宝资产数字)的相关文章

Android控件GridView之仿支付宝钱包首页带有分割线的GridView九宫格的完美实现

Android控件GridView之仿支付宝钱包首页带有分割线的GridView九宫格的完美实现 2015-03-10 22:38 28419人阅读 评论(17) 收藏 举报  分类: Android UI(819)  Android开发(1568)  关注finddreams:http://blog.csdn.net/finddreams/article/details/43486527 今天我们来模仿一下支付宝钱包首页中带有分割线的GridView,俗称九宫格.先上图,是你想要的效果么?如果

Android自定义view之仿支付宝芝麻信用仪表盘

自定义view练习 仿支付宝芝麻信用的仪表盘 对比图: 首先是自定义一些属性,可自己再添加,挺基础的,上代码 <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="RoundIndicatorView"> <!--最大数值--> <attr name="maxNum" form

Android例子源码仿支付宝手势密码的功能实现

本项目是一个仿支付宝手势密码部分的源码,项目在1280×720分辨率上显示有问题,在 854x480上没有问题,项目编码UTF-8默认编译版本4.4.2,实现思路: 1.要用一个类来表示这9个点中的第一个点.里面保留有当前点的上下左右的各个位置等属性: 2.自定义GroupView,用来装9个点,9个点的显示是通过ImageView.复写onLayout这个方法,让点按需求排列: 3.定义一个可以画线的View,复写onTouchEvent方法,在这个方法里面进行画直线的操作: 4.判断用户手指

Android例子源码仿支付宝手势密码的功能实

本项目是一个仿支付宝手势密码部分的源码,项目在1280×720分辨率上显示有问题,在 854x480上没有问题,项目编码UTF-8默认编译版本4.4.2,实现思路: 1.要用一个类来表示这9个点中的第一个点.里面保留有当前点的上下左右的各个位置等属性: 2.自定义GroupView,用来装9个点,9个点的显示是通过ImageView.复写onLayout这个方法,让点按需求排列: 3.定义一个可以画线的View,复写onTouchEvent方法,在这个方法里面进行画直线的操作: 4.判断用户手指

【开源项目解析】仿支付宝付款成功及&quot;天女散花&quot;效果实现——看PathMeasure大展身手

话说,在前面两篇文章中,我们学习了BitmapShader.Path的基本使用,那么这一篇文章,咱们接着来学习一下PathMeasure的用法.什么,你没听说过PathMeasure?那你就要OUT咯~ 项目效果图 PathMeasure介绍 仿支付宝实现原理解析 天女散花实现效果解析 更多参考资料 项目效果图 废话不多说,在开始讲解之前,先看下最终实现的效果. 效果一: 仿支付宝支付成功效果 效果二: 这两个项目都是使用Path和PathMeature配合完成的,由其他项目改造而来 项目一是七

[ios仿系列]仿支付宝手势解码

呀~.这么快就转到ios阵营了???.android还有那么多坑呢???为此我也仅仅能啃着馒头留下屈辱的眼泪了. . 本次因为开发公司产品的android版,继而ios版也负责一部分.当中一部分就是手势解锁的问题(为了要与android版一致,也算是非了一部分心血) 然而.但我打开iPhone,发现支付宝client已经没有手势解锁了,取而代之的时指纹解锁,关于指纹解锁,临时还来不及研究,仅仅能以后有机会再说了.. . 当然,支付宝android眼下还是手势解锁,所以也是为了与之相应(ios版如

Android插件化的思考——仿QQ一键换肤,思考比实现更重要!

Android插件化的思考--仿QQ一键换肤,思考比实现更重要! 今天群友希望写一个关于插件的Blog,思来想去,插件也不是很懂,只是用大致的思路看看能不能模拟一个,思路还是比较重要的,如果你有兴趣的话,也可以加群:555974449,你也可以说出你想看的Blog哦,嘿嘿!好的,不多说,我们进入正题: 关于QQ的换肤,他们的实现思路我不是很清楚,但是你可以看一下这张换肤的截图 我们想使用哪个主题就直接下载就好了,这一实现的过程我们大致的可以猜想: 首选是下载到本地指定文件夹,然后通过插件加载到我

仿支付宝/微信的密码输入框效果GridPasswordView解析

仿支付宝/微信的密码输入框效果GridPasswordView解析,把一些设置和一些关键的地方列了出来,方便大家使用,可能可以省一部分的时间,也算是自己的积累吧. 1.密码框可以输入的类型PasswordType public enum PasswordType { NUMBER, TEXT, TEXTVISIBLE, TEXTWEB; } 这里可以自行添加类型,然后在GridPasswordView中修改 @Override public void setPasswordType(Passwo

仿支付宝/微信的password输入框效果GridPasswordView解析

仿支付宝/微信的password输入框效果GridPasswordView解析,把一些设置和一些关键的地方列了出来,方便大家使用,可能能够省一部分的时间,也算是自己的积累吧. 1.password框能够输入的类型PasswordType public enum PasswordType { NUMBER, TEXT, TEXTVISIBLE, TEXTWEB; } 这里能够自行加入类型,然后在GridPasswordView中改动 @Override public void setPasswor