50 Android Hacks Hack7 在canvas上绘制动画

来源:互联网 发布:python getattr 编辑:程序博客网 时间:2024/05/16 11:38

《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,在画布上操作@Overrideprotected 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 reachedif (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 yif (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;}@Overrideprotected 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; @Overrideprotected 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