50 Android Hacks Hack7 在canvas上绘制动画

《50 Android Hacks 》这本书讲解了Android的50个小技巧,大家有空可以看看,也有不少人翻译。


书中源码作者奇托在:

Macarse/50AH-code · GitHub
https://github.com/Macarse/50AH-code


下面就按照我的理解逐一翻译一下 

Hack 7 在canvas上绘制动画

 我们要给控件实现动画效果,首先想到的是Android 的动画api,帧动画,补间动画,属性动画等,那我们那我们能不能直接画一个动画效果呢?

利用Canvas的刷新操作,对canvas不理解的可以查查资料,我们可以实现移动的动画,下面来实现一个在屏幕中随意移动的动画:



首先要准备一张画布,把画布放到我们的窗口中,还要准备一张移动的方块,当然方块我们也可以用paint自己画,这就要再套一层

为了实现画布,要扩展view,覆写onDraw(Canvas canvas)方法

小方块是一个独立的视图,这里不把小方块显示在activity中,在它外面又“包”了一层

画布代码:

package com.example.canvasanimation;

import android.annotation.SuppressLint;
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);
		mRectangle = new Rectangle(context, this);
		mRectangle.setARGB(255, 255, 0, 0);
		mRectangle.setSpeedX(3);
		mRectangle.setSpeedY(3);
	}
  //覆写 onDraw,在画布上操作

	@Override
	protected void onDraw(Canvas canvas) {
		invalidate();
		mRectangle.move();
		//矩形在同一块画布上画,mRectance外面又包了一层画布,为同一个画布
		mRectangle.onDraw(canvas);
		
	}

}

Rectangle就是屏幕中移动的红色方块,也可以放一张图片在屏幕中移动

Rectangle继承View类,重写onDraw()方法,并提供一些setter和getter方法,用于设置小方块的属性。判断碰撞事件的逻辑在moveTo()方法中。

Rectangle实现代码:

package com.example.canvasanimation;

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 {
	public static final int MAX_SIZE = 40;
	private static final int ALPHA = 255;
	private int mCoordX = 0;
	private int mCoordY = 0;
	private int mRealSize = 40;
	private int mSpeedX = 3;
	private int mSpeedY = 3;

	private boolean goRight = true;
	private boolean goDown = true;
	private DrawView mDrawView;

	private Paint mInnerPaint;
	private RectF mDrawRect;

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

		mInnerPaint = new Paint();

		mDrawRect = new RectF();

		/* Red is default */
		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);
	}

	public void setX(int newValue) {
		mCoordX = newValue;
	}

	public float getX() {
		return mCoordX;
	}

	public void setY(int newValue) {
		mCoordY = newValue;
	}

	public float getY() {
		return mCoordY;
	}

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

	private void moveTo(int goX, int goY) {

		// check the borders, and set the direction if a border has reached
		if (mCoordX > (mDrawView.width - MAX_SIZE)) {
			goRight = false;
		}

		if (mCoordX < 0) {
			goRight = true;
		}

		if (mCoordY > (mDrawView.height - MAX_SIZE)) {
			goDown = false;
		}
		if (mCoordY < 0) {
			goDown = true;
		}

		// move the x and y
		if (goRight) {
			mCoordX += goX;
		} else {
			mCoordX -= goX;
		}
		if (goDown) {
			mCoordY += goY;
		} else {
			mCoordY -= goY;
		}

	}

	public int getSpeedX() {
		return mSpeedX;
	}

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

	public int getmSpeedY() {
		return mSpeedY;
	}

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

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
         //设定 矩形的大小,参数为左上右下边界
		mDrawRect.set(mCoordX, mCoordY, mCoordX + mRealSize, mCoordY + mRealSize);
		//画圆角矩形。第一个5为x轴半径,第二个5为y轴半径
		canvas.drawRoundRect(mDrawRect, 5, 5, mInnerPaint);

	}

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

	public int getSize() {
		return mRealSize;
	}
}
最后把画布放到我们的窗口当中:

package com.example.canvasanimation;

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

public class MainActivity extends Activity {
	 private DrawView mDrawView; 
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		//获取窗口展示,包含窗口的宽度,长度
		Display display = getWindowManager().getDefaultDisplay();  
		//初始化DrawView
	    mDrawView = new DrawView(this);  
	    //将窗口的宽高,赋值给mDrawView的宽高,使其充满整个窗口
	    mDrawView.height = display.getHeight();  
	    mDrawView.width = display.getWidth();  
		
		 //把窗口设为activity的布局
		setContentView(mDrawView);
	}

}

当onDraw()方法被调用的时候,我们将会改变小方块的位置然后将它绘制到画布上。这里的invalidate()就是这个Hack的关键,这个函数的作用就是强制一个View进行绘制(即调用onDraw方法)。因此将invalidate()方法放到onDraw()方法里面就意味着每当View绘制完自己的时候就会马上调用invalidate()进行再次绘制。换个角度来看,我们其实就是在循环的调用小方块的move()方法和onDraw()方法来创建一个有趣的动画。

提示:

在onDraw()方法里面调用invalidate()方法来更新view的位置是创建动画的一种很简单的途径。如果做一个小游戏,用这个方式可以实现循环


源码大家去github上下载

点击打开链接

待续。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值