在Canvas上显示动画

如果想为自定义的UI控件添加动画效果,会发现动画相关的API是很有限的。那么有没有API可以直接向屏幕绘图呢?答案是肯定的。Android提供了Canvas满足这一要求。

在这个例子中,我们将以方块在屏幕上弹跳为例分析如何使用Canvas类在屏幕上绘制图形,并为其添加动画效果。应用程序最终效果如下:

这里写图片描述

我们先需要了解Canvas类的基本概念:“我们可以把Canvas视为Surface的替身或者接口,图形便是绘制在Surface上的。Canvas封装了所有绘图调用。通过Canvas,绘制到Surface上的内容首先存储到与之关联的Bitmap中,该Bitmap最终会呈现到窗口上。”

Activity代码如下:

package com.example.huangfei.hack;

import android.app.Activity;
import android.os.Bundle;
import android.view.Display;

public class MainActivity extends Activity {
    private DrawView mDrawView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //获取屏幕的宽和高
        Display display = getWindowManager().getDefaultDisplay();
        mDrawView = new DrawView(this);
        mDrawView.width = display.getWidth();
        mDrawView.height = display.getHeight();

        //以DrawView作为Activity的内容视图,DrawView占据所有可用空间
        setContentView(mDrawView);
    }

}

DrawView类代码如下:

package com.example.huangfei.hack;

import android.content.Context;
import android.graphics.Canvas;
import android.view.View;

/**
 * 该类负责在屏幕上绘制一个方块,并不断更新方块的位置
 */
public class DrawView extends View {
    private Rectangle mRectangle;
    public int width;
    public int height;

    public DrawView(Context context) {
        super(context);

        /**
         * 创建方块对象。Rectangle类内部实现了将自身绘制到Canvas上的逻辑,并且已经包含了正确变换其位置
         * 的代码逻辑。
         */
        mRectangle = new Rectangle(context, this);
        mRectangle.setARGB(255, 255, 0, 0);
        mRectangle.setSpeedX(3);
        mRectangle.setSpeedY(3);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        mRectangle.move();//变换方块位置
        mRectangle.onDraw(canvas);//将方块绘制到Canvas上

        /**
         *invalidate()方法强制重绘视图。把该方法放在onDraw()的目的是为了在View绘制完自身后,可以立即重新
         * 调用onDraw()。换句话说,通过循环调用Rectangle的move()和onDraw()方法实现了一个动画效果。
         */
        invalidate();
    }
}

Rectangle类代码如下:

package com.example.huangfei.hack;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.view.View;

/**
 * 创建一个方块
 */
public class Rectangle extends View {
    private static final int MAX_SIZE = 40;//方块距右端或底部的距离,一般为方块的大小mRealSize
    private static final int ALPHA = 255;//画笔的透明度

    private DrawView mDrawView;
    private Paint mInnerPaint;//画笔
    private RectF mDrawFect;//矩形坐标

    private float mCoordX;//方块当前x轴位置
    private float mCoordY;//方块当前Y轴位置
    private int mRealSize = 40;//方块的大小
    private int mSpeedX = 3;//方块x轴每次移动的距离
    private int mSpeedY = 3;//方块轴每次移动的距离

    private boolean goRight = true;//是否向右移动
    private boolean goDown = true;//是否向下移动

    public Rectangle(Context context, DrawView drawView) {
        super(context);

        mDrawView = drawView;
        mInnerPaint = new Paint();
        mDrawFect = new RectF();

        //设置画笔的默认颜色为红色
        mInnerPaint.setARGB(ALPHA, 255, 0, 0);
        //处理画笔的锯齿
        mInnerPaint.setAntiAlias(true);
    }

    public void setARGB(int a, int r, int g, int b) {
        mInnerPaint.setARGB(a, r, g, b);
    }

    @Override
    public float getX() {
        return mCoordX;
    }

    @Override
    public void setX(float x) {
        mCoordX = x;
    }

    @Override
    public float getY() {
        return mCoordY;
    }

    @Override
    public void setY(float y) {
        mCoordY = y;
    }

    public int getSize() {
        return mRealSize;
    }

    public void setSize(int realSize) {
        mRealSize = realSize;
    }

    public int getSpeedX() {
        return mSpeedX;
    }

    public void setSpeedX(int speedX) {
        mSpeedX = speedX;
    }

    public int getSpeedY() {
        return mSpeedY;
    }

    public void setSpeedY(int speedY) {
        mSpeedY = speedY;
    }

    public void move() {
        moveTo(mSpeedX, mSpeedY);
    }

    private void moveTo(int goX, int goY){
        //判断X轴方向的边界
        if(mCoordX > mDrawView.width - MAX_SIZE){
            goRight = false;
        }
        if(mCoordX < 0){
            goRight = true;
        }

        //判断Y轴方向的边界
        if(mCoordY > mDrawView.height - MAX_SIZE){
            goDown = false;
        }
        if(mCoordY < 0){
            goDown = true;
        }

        //移动方块
        if(goRight){
            mCoordX += goX;
        }else{
            mCoordX -= goX;
        }
        if(goDown){
            mCoordY += goY;
        }else{
            mCoordY -= goY;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        mDrawFect.set(mCoordX, mCoordY, mCoordX + mRealSize, mCoordY + mRealSize);
        canvas.drawRoundRect(mDrawFect, 0, 0, mInnerPaint);
    }
}

在onDraw()方法中通过调用invalidate()方法变换视图的位置是实现自定义动画的简单方法。如果你想开发一款小游戏,使用这个小技巧处理游戏的主循环是一个简单的方法。

代码地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值