自定义View中的动画

今天研究了一下自定义View中的动画。
绘制View中的动画可以使用Animation来实现,例如我们要实现动态绘制一个圆圈,绘制的主要代码使用canvas接口:

public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint)

大体步骤如下:
1.自定义Animation类
2.覆写回调函数applyTransformation
3.applyTransformation函数中通过时间变量interpolatedTime控制该时刻绘制的图形
4.在自定义View中适时触发animation,完成动画绘制

对应代码如下:

class MyAnimation extends Animation {

    // 这里interpolatedTime是归一化的时间变量,速率由animation设定的持续时间决定
    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        super.applyTransformation(interpolatedTime, t);
        // 通过角度数值乘以时间变量,调整当前绘制的角度值
        mCurrentDegree = (int) (interpolatedTime * CIRCLE_DEGREE);
         // 对绘图频率做限定,以降低资源消耗
         if (mCurrentDegree%4 == 0) {
            // 异步的发起绘图请求
            postInvalidate();
        }
    }
}

在这里,开始动画以后applyTransformation函数会自动调用,
时间变量参数interpolatedTime在0-1之间变化,变化的速率会根据animation设置的持续时间所改变。
为了避免频繁绘制占用过多CPU资源,通过计算角度,以降低绘制的频率。

在View构造函数中,来初始化animation:

public XCustomView(Context context, AttributeSet attrs) {
    super(context, attrs);

    anim = new MyAnimation();
    anim.setDuration(3000);    // 设置动画持续时间
    anim.setRepeatMode(Animation.RESTART);
    anim.setRepeatCount(Animation.INFINITE);    // 设置动画重复播放,播放次数无穷次(无限循环)

}

在这里我们设置了animation动画的属性,包括持续时间,重复播放的模式以及重复的次数,通过指定Animation.INFINITE,动画将无限循环播放下去。

设置好animation以后,需要自动触发或是通过点击事件触发,调用View的startAnimation接口即可,在这里我们自动调用触发动画播放:

@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    this.startAnimation(anim);
}

在animation中,我们在回调函数中动态的更改了角度数值;
调用postInvalidate,会触发onDraw绘制函数的调用;
因此在onDraw里使用变化后的角度,重新绘制曲线即可,连续重复的调用(绘制)就会产生动画效果。

包括onDraw的最后整体代码如下:

public class XCustomView extends View {

    public static final String TAG = "CustomView-TAG";
    private static final int CIRCLE_DEGREE = 360;

    private Paint mPaint = new Paint();

    private RectF arc = new RectF(0, 0, 100, 100);

    int mWidth = 0;
    int mHeight = 0;

    int mCurrentDegree = 0;

    private MyAnimation anim;

    // 构造函数中初始化Animation参数
    public XCustomView(Context context, AttributeSet attrs) {
        super(context, attrs);

        anim = new MyAnimation();
        anim.setDuration(3000);
        anim.setRepeatMode(Animation.RESTART);
        anim.setRepeatCount(Animation.INFINITE);

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        Log.d(TAG, "inner onMeasure");
        mWidth = MeasureSpec.getSize(widthMeasureSpec);
        mHeight = MeasureSpec.getSize(heightMeasureSpec);

        arc.set(0, 0, mWidth, mWidth);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        Log.d(TAG, "inner onLayout");
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.d(TAG, "inner onDraw");

        canvas.drawColor(Color.BLUE);

        mPaint.setColor(Color.WHITE);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setAntiAlias(true);

        canvas.drawArc(arc, 0, mCurrentDegree, true, mPaint);    // 绘制曲线
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        this.startAnimation(anim);
    }

    class MyAnimation extends Animation {
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            super.applyTransformation(interpolatedTime, t);

            mCurrentDegree = (int) (interpolatedTime * CIRCLE_DEGREE);

            if (mCurrentDegree%4 == 0) {
                postInvalidate();
            }
        }
    }
}

运行以后CPU占用一直在5-8%,后面再研究其他实现方式比较一下……

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页