Draw with a Canvas

本文介绍如何在Android应用中利用Canvas进行图形绘制。通过View和SurfaceView两种方式,文章详细阐述了如何实现自定义绘制过程,包括如何创建Canvas、如何在Canvas上绘制Bitmap、Rect和Text等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Draw with a Canvas 通过Canvas进行绘制

当你正在写一个应用,这个应用需要一些特殊的绘制,或者需要控制动画的图片,你可以达到次目的通过绘制到一个Canvas.这个Canvas像一个中介,或者说一个接口,他把你的绘制和你的图形将要绘制的实际surface联系起来,它处理你所有的draw操作。通过Canvas,你的绘制实际操作在一个下层的Bitmap.这个Bitmap将会放置到
窗口。
在你绘制图形的onDraw回调事件中,他提供了Canvas,你仅仅需要把所有的draw方法都操作在这个Canvas上面。当你是操作SurfaceView对象时,你也可以通过调用SurfaceHolder.lockCanvas()来获取一个Canvas(这两种情形都在下面的章节中讨论)。但是,如果你需要创建一个Canvas,那么你需要同时创建一个Bitmap,Bitmap才是承载实际绘制操作的载体。对于Canvas来说,Bitmap总是需要的,你可以像下面这样设置一个新的Canvas:
Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
现在你的Canvas将会在定义的Bitmap上进行绘制。通过Canvas绘制完毕后,你可以把Bitmap移动到另一个Canvas,通过一个如下的方法:canvas.drawBitmap(Bitmap,...)。推荐最后把你的最终图像绘制到 一个Canvas上,该 Canvas通过View.onDraw()或 SurfaceHolder.lockCanvas()传递给你。(查看下面的章节)
Canvas类提供了许多绘制图像的方法,例如 drawBitmap(...),drawRect(...),drawText(...),等等。其他的你使可能使用的类也坑害有draw方法。例如,你可能有一些Drawable对象,你想把他们绘制到一个Canvas上。Drawable自己拥有draw方法,而在该方法中需要一个Canvas参数。
通过View
如果你的应用不要求很高处理速度,或者画面的切换速度比较慢,例如一个象棋程序,或者贪蛇吃游戏,或者其他的慢动画应用,在这些情况下,你可以考虑创建一个自定义的View组件,并且把图形绘制到View.onDraw()函数中的Canvas上。这么做最方
便的事情就是Android框架将会给你提供一个预先定义的Canvas来供你的绘制接口调用。
开始,你需要从View类(或者其子类)继承定义一个自定义的类,并实现onDraw方法。onDraw方法将会由Android框架调用来,你需要在这个方法中绘制自己的View。也就是在这里,通过onDraw回调传递下来Canvas,你可以进行各种绘制操作。
Android框架层也只会在需要的时候才会调用onDraw()方法。每当你的应用准备绘制的时候,你必须请求View通过调用invalidate来更新。这意味这你的应用需要刷新,然后Android框架就会回到你的onDraw()方法,尽管他不保证是立即调用。
在你的View的onDraw()方法中,使用为你准备好的View来做所有的绘制工作,使用各种Canvas的绘制方法,或者其他类的draw()方法,他使用你的Canvas作为一个参数。一旦onDraw方法调用完成,Android系统将会使用你的Canvas来绘制一个Bitmap.
注意,如果你需要在非UI线程中请求一个刷新,你需要调用postInvalidate()方法。
要获取更多的关于View类的信息,查看 Building Custom Components。
在SDK实例中的Snake game 是一个这方面应用程序的实例。
通过SurfaceView
SurfaceView是View的一个特殊子类,他里面提供了一个专门的surface.这么做的目地是为应用的第二线程提供一个绘制surface,这样应用就不需要等到系统的绘制系统准备好可以绘制。这样的话,拥有SurfaceView引用的其他线程就可以按照他的步调来绘制自己的Canvas.
首先,你需要创建一个类继承自SurfaceView。这个自定义的类要实现SurfaceHolder.Callback。这个子类将会祈祷一个接口的作用,他将会给你发出一些关于你里面的surface的信息,如当他创建或销毁的时候。这些信息是非常重要的,通过它你可以知道合适开始绘制,你是否需要根据新的surface属性来做一些调整。以及合适停止绘制和杀死一些潜在的任务。在你的SurfaceView内部是定义第二个线程的好地方,在这个线程里你可以执行所有的关于你的Canvas的绘制程序。
你应该通过SurfaceHolder而不是直接通过Surface来操作自己。因此,当你的SurfaceView初始化的时候,你需要通过getHolder()来获取一个SurfaceHolder,你也应该通过调用addCallback(传递this指针)来告诉SurfaceHolder你想接受一些SurfaceHolder的回调(通过SurfaceHolder.callback).然后在你的SurfaceView类不重写每个SurfaceHolder.callback方法。
注意,在每次你通过SurfaceHolder获取的Canvas里面,先前的Canvas状态会残留着。为了正确的显示你的图像,你必须重绘整个surface.例如,你可以清除前面的状态通过调用drawColor()给Canvas填充一个颜色或者通过调用drawBitmap()来设置一个背景图片。否则的话,你将会看到你先前绘制图片的残留痕迹。
该方面的一个示例程序,查看SDK实例文件中的Lunar Lander游戏,或者查看Sample Code章节的代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值