支付宝更新9.0后,细心的朋友会发现新增了一个动画效果,就是进入我的钱包的时候,我的余额会有一段滚动显示的动画效果,比如说你有100块,余额就从0滚动到100,看到自己的钱在不断涨,让我们这些穷屌丝莫名产生一种似乎很有钱的幻觉,于是就会带着这种幻觉想要去天猫消费消费。。。于是我也仿了一个支付宝的滚动效果,如下图,也许这样能让我们的用户也感觉自己很有钱。
仿支付宝滚动效果:
在做这个效果之前,我也习惯性的在网上搜索了一番,做这种效果的比较少,但也能找到这样的开源代码,自己也下下来看了一下,但是自己感觉不好的是网上把这种效果做成了一个控件,继承TextView来实现这样的效果,而且一个库好歹也有5、6个类,实在有点杀鸡用牛刀的感觉,于是自己写了一下,实际实现代码100行都不到。我把它封装成一个静态工具类,方便调用:
先放使用方法,在上代码。
使用方法:
把NumAnim类添加到自己工程在需要使用滚动效果的地方调用startAnim方法即可,例如:NumAnim.startAnim(textView, 1253.47); //第二个参数是textView要显示的价格
滚动时间默认是500毫秒,如果你需要自己设置,可以调用下面的重置方法:
NumAnim.startAnim(textView, 1253.47, 1000);//设置滚动动画持续1秒
下面上NumAnim类源码:
NumAnim.java:
import java.util.LinkedList;import java.util.Random;import android.widget.TextView;import rv.cber.util.NumUtil;public class NumAnim {//每秒刷新多少次private static final int COUNTPERS = 100;public static void startAnim(TextView textV, float num) {startAnim(textV, num, 500);}public static void startAnim(TextView textV, float num, long time) {if (num == 0) {textV.setText(NumUtil.NumberFormat(num,2));return;}Float[] nums = splitnum(num, (int)((time/1000f)*COUNTPERS));Counter counter = new Counter(textV, nums, time);textV.removeCallbacks(counter);textV.post(counter);}private static Float[] splitnum(float num, int count) {Random random = new Random();float numtemp = num;float sum = 0;LinkedList<Float> nums = new LinkedList<Float>();nums.add(0f);while (true) {float nextFloat = NumUtil.NumberFormatFloat((random.nextFloat()*num*2f)/(float)count, 2);System.out.println("next:" + nextFloat);if (numtemp - nextFloat >= 0) {sum = NumUtil.NumberFormatFloat(sum + nextFloat, 2);nums.add(sum);numtemp -= nextFloat;} else {nums.add(num);return nums.toArray(new Float[0]);}}}static class Counter implements Runnable {private final TextView view;private Float[] nums;private long pertime;private int i = 0;Counter(TextView view,Float[] nums,long time) {this.view = view;this.nums = nums;this.pertime = time/nums.length;}@Overridepublic void run() {if (i>nums.length-1) {view.removeCallbacks(Counter.this);return;}view.setText(NumUtil.NumberFormat(nums[i++],2));view.removeCallbacks(Counter.this);view.postDelayed(Counter.this, pertime);}}}
注意上面代码,直接导入会报错,因为你没有NumUtil.NumberFormat()和NumberFormatFloat()这2个方法,这个方法我写在工具类里的,作用是保留2位小数,一个返回String一个返回float,我把这2个方法贴上,自行添加:
public static String NumberFormat(float f,int m){return String.format("%."+m+"f",f);}public static float NumberFormatFloat(float f,int m){String strfloat = NumberFormat(f,m);return Float.parseFloat(strfloat);}
其实也就2行而已。
下面解释下源码:
其实就是通过一种算法把价格拆分成了n个float组成的集合,然后在使用循环把这些float设置到TextView上。
这里主要利用了View的postDelayed(Runable action, int delayMillis)方法给TextView设置一个Runable线程对象在delayMillis毫秒后执行,我们自定义这个Runable,在线程主方法run()中重复调用postDelayed(…)来实现循环执行动画的效果。
@Overridepublic void run() {if (i>nums.length-1) {view.removeCallbacks(Counter.this);return;}view.setText(NumUtil.NumberFormat(nums[i++],2));view.removeCallbacks(Counter.this);view.postDelayed(Counter.this, pertime);}
这个方法其实并没有什么动画,而是重复调用setText来设置不同的价格,这个价格来自于一个float数组nums[]
就是说我们在调用post方法前,先需要把我们的价格num拆分成n个float的集合,集合每一个float就是动画过程中显示的数字,如下举例:
//假如传入的价格num为: 1024.32 //那么我们期望获得下面这样一个集合:24.2356.44123.34353.12745.2876.561003.031024.32//这样就可以把上面这组数据依次显示上去就可以了
那么我们怎么来获得这个集合呢?我提供了一个算法,方法如下:
private static Float[] splitnum(float num, int count) {Random random = new Random();float numtemp = num;float sum = 0;LinkedList<Float> nums = new LinkedList<Float>();nums.add(0f);while (true) {float nextFloat = NumUtil.NumberFormatFloat((random.nextFloat()*num*2f)/(float)count, 2);System.out.println("next:" + nextFloat);if (numtemp - nextFloat >= 0) {sum = NumUtil.NumberFormatFloat(sum + nextFloat, 2);nums.add(sum);numtemp -= nextFloat;} else {nums.add(num);return nums.toArray(new Float[0]);}}}
这个方法就是用来拆分价格,获取一个递增集合的,这里我严格限制结果保留2位小数,需要自定义可以自行修改,方法的第一参数num是需要拆分的数,方法的第二个参数count是指期望这个数被拆分成多少份。但这个count并不是绝对的,可能会比你期望的多一些或者少一些。因为方法中使用随机函数来生成每一个float,产生的随机数数量会接近你设置的count但并不一定相等。
具体实现就看看代码把,十几行代码相信看得懂没问题。
我仔细观察注意到支付宝的余额滚动效果有一个慢慢递减的过程,就是说,开始滚动一下的数字累加得比较大,可能是1000,2000(根据你的余额决定),到后面就比较小比如0.5,0.05 。这样会使动画产生一个慢慢首尾的效果,感觉先滚动高位的数字,到最后,高位不变了接着滚动末尾的数字,这样的效果更加流畅平滑。如果感兴趣的朋友也想要这样的效果,那就重写上面的splitnum()方法吧,使这个方法产生的float,先产生大数字,慢慢减小,最后产生小数。这样执行起来就和支付宝非常类似了。