Android Canvas绘制图形-拾音器之动画篇

Android Canvas绘制图形 拾音器之动画篇

标签 Android Canvas View Animation ValueAnimator View动画 属性动画

前几天我写过一篇文章,叫Android Canvas 绘制图形 – 拾音器,那篇文章旨在讲解如何使用Canvas来绘制图形,并没有实现指针的偏转动画实现,那么,今天我们就来看看指针的偏转动画如何实现。

知识准备

安卓上实现动画的方式分为两种,一种是View动画,包名:android.view.animation,另一种是属性动画,包名:android.animation

View动画从字面上理解就是作用对象只能是View的派生类,其他的就只能心有余而力不足了。

属性动画的作用对象就不只是针对View的派生类了,他能操作很多属性,比如改变一个控件的宽高值;一个数值平滑过渡到另一个数值等,总之,View动画能做的他能做,View动画不能做的他也能做。对,你没看错,就是这么屌!

简单介绍

View动画,包括以下几种类型:

类型 说明
AlphaAnimation 渐变透明度
RotateAnimation 画面旋转
ScaleAnimation 尺寸缩放
TranslateAnimation 位置移动

属性动画(Property Animation),包括以下几种类型:

类型 说明
ObjectAnimator 动画执行类,对对象进行操作
ValueAnimator 动画执行类,对数值进行操作

今天我们将使用到的是ValueAnimation类,接下来对动画进行分析,看看要实现指针偏转的动画需要用到什么方法。

  1. 指针偏转是通过旋转角度来实现的,如果我们要使偏转产生动画,就需要动态的改变旋转的角度。
  2. 旋转的角度参数类型是float,在ValueAnimator类中的ofFloat()方法正好是动态改变float数值的,所以我们要用到它。
  3. 数值每改变一次,我们都要把变化后的数值赋给rotate()方法,使指针旋转相应角度,所以这里需要对数值变化进行监听,因此会用到addUpdateListener()方法
  4. 赋值给rotate()方法后,需要对视图进行重绘,因此我们需要用到视图绘制过程中的invalidate()方法

思路

这里我们用mValue表示指向数值,用变量mAngle表示通过计算后的偏转角度

通常的做法,我们都是在Activity或者Fragment里通过调用一个方法,将指针要指向的数值(mValue)数的方式传递过去,这样的话,我们就有两种思路。

一:使用ofFloat()方法动态改变指针指向的数值,即传递过来的参数mValue

二:将传递过来的参数进行计算成指针偏转的角度(mAngle),然后使用ofFloat()方法动态改变角度数值

这两种方法都是可取的,具体情况具体分析,由于在界面上我们要动态显示指针指向的数值,如果采用第二种的话,那么我们要计算两次,一次是将指向mValue计算为mAngle,数值动态变化后还要将mAngle计算为mValue,这样比较麻烦,所以我们采用第一种思路。

因此,要实现指针的偏转动画,代码可以这么写:

private int mMaxValue = 50;  //分值区间的最大值
private int mMinValue = -50; //分值区间的最小值
/**输入值,通过输入值来计算指针的旋转角度,即{@mAngle}的值,
 * 最终在界面上呈现的效果是指针指向输入值的刻度上*/
private String mValue = "- -";
/**刻度盘呈现的总弧度,本案例中总弧度为180,呈半圆形*/
private float mArc = 180f;
/**指针旋转角度值*/
private float mAngle = 0f;

...

/**
 * 设置指针指向数值,并产生旋转动画
 * 这里我们动态改变指向数值
 * @param value 指向数值
 */
public void setValue(float value){
    //{@param value}为指针将要指向的数值,即界面上看到的数值
    ValueAnimator startAnimator = ValueAnimator.ofFloat(0, value);

    startAnimator.addUpdateListener(
       new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            //通过getAnimatedValue()取变化后的值
            float md = (float) animation.getAnimatedValue();
            //计算指针当前应该偏转的角度
            mAngle = md * (mArc / (float) (mMaxValue - mMinValue));
            //界面上显示当前指针显示的数值
            mValue = String.valueOf((int)md);
            //调用重绘方法
            invalidate();

        }
    });
    startAnimator.setDuration(1000);
    startAnimator.start();
}

setValue()方法里我们动态的改变了指针指向的数值和指针偏转的角度,并把这两个数值分别存放在全局变量mValuemAngle,这样一来,我们只需要在onDraw()方法中,对指针进行旋转和但前指向数值的显示就可以了,代码如下:

/**
 * 注意:
 * 下方的所以坐标计算和长度计算都是依据在屏幕宽度为621px情况下的
 * @param canvas
 */
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    ...

    System.out.println("mAngle ==>" + mAngle);
    canvas.rotate(mAngle, xc, yc);

    //画指针
    /**
     * xc * 0.101449 = 深色刻度线条的长度
     * mWidth * 0.064412 = 在屏幕宽度为621下,长度为40
     * 所以下面第三个参数的值可以理解为距离深色刻度线下方有40倍数的间隙
     */
    canvas.drawLine(xc, yc,
            xc - radius + (xc * 0.101449f + mWidth * 0.064412f),
            yc + 3, paintCursor);

    ...

    //值
    pitchValuePaint.setAntiAlias(true);
    pitchValuePaint.setTextSize((mWidth * 0.080515f));
    pitchValuePaint.setColor(getResources().getColor(R.color.colorAccent));

    canvas.drawText(mValue,
            xc - pitchValuePaint.measureText(mValue) / 2,
            yc + (xc * 0.481481f + mWidth * 0.209339f),
            pitchValuePaint);
    ...
}

效果如下:

详细的代码,请移步到我的GitHub:https://github.com/zhongzilu/TunerView

我是钟子路,Thanks for watching!

本文总阅读量