android开发游记:仿支付宝余额数字累加滚动效果的实现

支付宝更新9.0后,细心的朋友会发现新增了一个动画效果,就是进入我的钱包的时候,我的余额会有一段滚动显示的动画效果,比如说你有100块,余额就从0滚动到100,看到自己的钱在不断涨,让我们这些穷屌丝莫名产生一种似乎很有钱的幻觉,于是就会带着这种幻觉想要去天猫消费消费。。。于是我也仿了一个支付宝的滚动效果,如下图,也许这样能让我们的用户也感觉自己很有钱。

仿支付宝滚动效果:

在做这个效果之前,我也习惯性的在网上搜索了一番,做这种效果的比较少,但也能找到这样的开源代码,自己也下下来看了一下,但是自己感觉不好的是网上把这种效果做成了一个控件,继承TextView来实现这样的效果,而且一个库好歹也有5、6个类,实在有点杀鸡用牛刀的感觉,于是自己写了一下,实际实现代码100行都不到。我把它封装成一个静态工具类,方便调用:

先放使用方法,在上代码。

使用方法:

  1. 把NumAnim类添加到自己工程
  2. 在需要使用滚动效果的地方调用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 com.ccrv.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 nums = new LinkedList();
        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;
        }

        @Override
        public 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(…)来实现循环执行动画的效果。

    @Override
    public 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.23
56.44
123.34
353.12
745.2
876.56
1003.03
1024.32
//这样就可以把上面这组数据依次显示上去就可以了

那么我们怎么来获得这个集合呢?我提供了一个算法,方法如下:

    private static Float[] splitnum(float num, int count) {
        Random random = new Random();
        float numtemp = num;
        float sum = 0;
        LinkedList nums = new LinkedList();
        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,先产生大数字,慢慢减小,最后产生小数。这样执行起来就和支付宝非常类似了。

你可能感兴趣的:(android,开发)