在 Canvas 上显示动画

本文来自 Android开发必知的50个诀窍 hack7

1.1 Canvas 介绍

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

Android框架规定,要绘制一些内容.需要四个基本要素:
A Bitmap to hold the pixels
A Canvas to host the draw calls (writing into the bitmap)
A drawing primitive (e.g. Rect, Path, text, Bitmap)
A paint (to describe the colors and styles for the drawing).


1.2 预期结果
如下,自定义View占据整个屏幕,在他的 Canvas 上动态的绘制矩形


1.3 首先我们创建一个 Activity 并把其 ContentView 设置为下面自定义的 MoveRectView

public class Hack5Activity extends Activity {

  private MoveRectView mMoveView;
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mMoveView = new MoveRectView(this);
    setContentView(mMoveView);
  }
}

1.4 完成 MoveRectView
创建 MoveRectView extends View 然后重写 onDraw() 方法

 @Override
    protected void onDraw(Canvas canvas) {
        mDrawRect.set(rectLeft, rectTop, rectLeft + rectWidth, rectTop + rectHeight);
        canvas.drawRoundRect(mDrawRect, 0, 0, mInnerPaint);
        changePos();//改变位置
    }

我们利用 canvas 来绘制矩形,然后通过改变矩形的位置来实现动画效果

     //改变位置
    protected void changePos() {
        //x坐标
        if (rectLeft > width - rectWidth) {
            goRight = false;
        }
        if (rectLeft < 0) {
            goRight = true;
        }
        if (goRight) {
            rectLeft += xSpeed;
        } else {
            rectLeft -= xSpeed;
        }

        //y坐标
        if (rectTop > height - rectHeight) {
            goBottom = false;
        }
        if (rectTop < 0) {
            goBottom = true;
        }
        if (goBottom) {
            rectTop += ySpeed;
        } else {
            rectTop -= ySpeed;
        }
        //重新绘制,触发 onDraw()
        postInvalidate();
    }

位置的改变以屏幕的宽高做限.只需要改变 left 和 top 这两个值就可以. 最后的 postInvalidate(); 会再次出发 onDraw() 来绘制,从而形成循环.


1.5 MoveRectView 源码

public class MoveRectView extends View {
    private static final int ALPHA = 255;
    private int rectLeft = 0;
    private int rectTop = 0;
    private static final int rectWidth = 40;
    private static final int rectHeight = 40;
    private Paint mInnerPaint;
    private RectF mDrawRect;
    public int width;
    public int height;

    private boolean goRight = true;
    private boolean goBottom = true;
    private int xSpeed = 5;
    private int ySpeed = 5;

    public MoveRectView(Context context) {
        super(context);
        mInnerPaint = new Paint();
        mDrawRect = new RectF();
        mInnerPaint.setARGB(ALPHA, 255, 0, 0);
        mInnerPaint.setAntiAlias(true);
        System.out.println("绘图初始化");
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = getMeasuredWidth();
        height = getMeasuredHeight();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        mDrawRect.set(rectLeft, rectTop, rectLeft + rectWidth, rectTop + rectHeight);
        canvas.drawRoundRect(mDrawRect, 0, 0, mInnerPaint);
        changePos();
    }

    //改变位置
    protected void changePos() {
        //x坐标
        if (rectLeft > width - rectWidth) {
            goRight = false;
        }
        if (rectLeft < 0) {
            goRight = true;
        }
        if (goRight) {
            rectLeft += xSpeed;
        } else {
            rectLeft -= xSpeed;
        }

        //y坐标
        if (rectTop > height - rectHeight) {
            goBottom = false;
        }
        if (rectTop < 0) {
            goBottom = true;
        }
        if (goBottom) {
            rectTop += ySpeed;
        } else {
            rectTop -= ySpeed;
        }
        //重新绘制,触发 onDraw()
        postInvalidate();
    }

}

备注

关于控件高度 height 的值.
height 的取值是在构造方法中: height = getMeasuredHeight();
1 这个方法返回的高度是去除掉屏幕状态栏的
2 内置软件盘的手机,当软键盘的显示状态发生变化时,会触发构造方法来更新高度.
因此最初设计认为高度范围的限制比较麻烦的情况就不存在了.

高度去除了状态栏,下面才是 MoveRectView 的地盘
这里写图片描述

内置软键盘,红色矩形到底其顶部就会返回
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值