Android TextView数字增长动画效果

某些app上,新进入一个Activity的时候,上面的一个关键性数字(比如金额)会以一个数字不断变大的动画来显示。刚开始的时候,想到的一个方案是:使用Thead+Handler,给定一个动画总时长与刷新间隔时长,根据公式(数字从0开始,每次增长值为数组除以动画执行次数,动画执行次数等于动画总时长除以刷新间隔时长);

每隔一段时间重新设置TextView的字符串为增加后的值,直到动画结束显示最终结果。
其实对安卓动画有一定了解的应该都知道ValueAnimator这个类,我们可以使用它来很好的实现所要的效果,而不需要我们自己来生硬的控制隔多久就增加多少刷新显示。根据ValueAnimator的属性方法以及实际需要,我们封装一个自定义View来实现我们的需求。

先看一下我实现的效果图

接下来上关键代码:

自定义View,其实就是继承一个TextView,代码实现很简单,代码中也有注释

/**
 * Created by dingchao on 2018/3/27.
 */

public class DcTextViewRunNumber extends TextView {

    /**
     * 延迟
     */
    private final int DELAY = 20;
    /**
     * 保留小数位数  默认2为
     */
    private final int DECIMALS_COUNT = 2;
    private final int START_RUN = 101;
    private final int STOP_RUN = 102;
    /**
     * 跑的次数
     */
    private final int RUN_COUNT = 40;
    private float speed;
    private float startNum;
    private float endNum;
    /**
     * 保留小数位数
     */
    private int decimals = DECIMALS_COUNT;
    /**
     * 每次跑的次数
     */
    private int runCount = RUN_COUNT;
    /**
     * 动画延迟
     */
    private int delayMillis = DELAY;
    private boolean isAniming;

    private Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            if (msg.what == START_RUN) {
                if(speed==0){
                    if(endNum!=0){
                        speed = getSpeed();
                        startNum = speed;
                    }else{
                        return ;
                    }
                }
                isAniming = !running();
                if (isAniming) {
                    sendEmptyMessageDelayed(START_RUN, delayMillis);
                }else{
                    speed = 0;
                    startNum = 0;
                }
            }
        };
    };

    public DcTextViewRunNumber(Context context) {
        super(context);
    }

    public DcTextViewRunNumber(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public DcTextViewRunNumber(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * 开始数字跳动动画
     * @return 动画是否结束
     */
    private boolean running() {
        setText(withDEC(String.valueOf(startNum)) + "");
        startNum +=speed;
        if(startNum >= endNum){
            setText(withDEC(String.valueOf(endNum)) + "");
            return true;
        }
        return false;
    }

    /**
     * 计算速度
     * @return
     */
    private float getSpeed(){
        float speedFloat = withDEC(String.valueOf(endNum/runCount)).floatValue();
        return speedFloat;
    }

    /**
     * 判断是否是非负数
     * @return
     */
    private boolean isNumber(String num){
        if("".equals(num) || num==null)
            return false;
        Pattern pattern = Pattern.compile("^\\d+$|\\d+\\.\\d+$");
        Matcher matcher = pattern.matcher(num);
        return matcher.find();
    }

    /**
     * 取整四舍五入 保留小数
     * @param num
     * @return
     */
    private BigDecimal withDEC(String num){
        return new BigDecimal(num).setScale(decimals, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 设置显示的数字
     * @param num
     */
    public void setShowNum(String num){
        setShowNum(num,DECIMALS_COUNT);
    }

    /**
     * 设置显示的数字
     * @param num
     * @param decimals  要保留的小数位
     */
    public void setShowNum(String num,int decimals){
        if(!isNumber(num)){
            return;
        }
        setText(num);
        setDecimals(decimals);
    }

    /**
     * 开始跑
     */
    public void startRun(){
        if(isAniming){
            return ;
        }
        if(isNumber(getText().toString())){
            endNum = withDEC(getText().toString()).floatValue();
            mHandler.sendEmptyMessage(START_RUN);
        }
    }

    public int getDecimals() {
        return decimals;
    }

    /**
     * 设置保留的小数位     0:不保留小数
     * @param decimals
     */
    public void setDecimals(int decimals) {
        if(decimals>=0){
            this.decimals = decimals;
        }
        setText(withDEC(getText().toString())+"");
    }

    public int getRunCount() {
        return runCount;
    }

    /**
     * 设置动画跑的次数
     * @param runCount
     */
    public void setRunCount(int runCount) {
        if(runCount<=0){
            return ;
        }
        this.runCount = runCount;
    }

    public int getDelayMillis() {
        return delayMillis;
    }

    /**
     * 设置动画延迟
     * @param delayMillis
     */
    public void setDelayMillis(int delayMillis) {
        this.delayMillis = delayMillis;
    }

接下来看怎么使用,MainActivity.java中

public class MainActivity extends AppCompatActivity {
    private DcTextViewRunNumber numberRunView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        numberRunView = (DcTextViewRunNumber) findViewById(R.id.numberRunView);
        numberRunView.setShowNum("711", 0);//终止的数字,小数点,这里为0所以没有小数点
        numberRunView.setRunCount(50);//动画执行的次数,50次执行完
//        numberRunView.setShowNum("221.918899");
        numberRunView.startRun();//
    }

    /**
     * @param view
     */
    public void runClick(View view) {
        numberRunView.startRun();
    }

}

activity_main.xml也贴一下吧,贴全了吧

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <cn.up.com.textviewrun.DcTextViewRunNumber
        android:id="@+id/numberRunView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="123"
        android:textSize="30sp" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="runClick"
        android:text="跑" />

</LinearLayout>

主要的就是这三个文件,代码都全部贴出来了,效果也还可以。开发中不要重复造轮子,有的改一下就可以直接用咯。

posted @ 2018-03-27 17:58  丁先森  阅读(2017)  评论(0编辑  收藏  举报