前面在自定义View中进行了绘图,但View的绘图机制存在如下缺陷。
(1)View缺乏双缓冲机制。
(2)当程序需要更新View中的图像时,程序必须重绘View上显示的整张图片。
(3)新线程无法直接更新View组件。
由于View存在上面缺陷,在游戏开发中一般使用SurfaceView来进行绘制,SurfaceView不同于View,它可以在非UI线程中绘制并显示在界面上,这意味着您可以自己新开一个线程,然后把绘制渲染的代码放在该线程中。SurfaceView一般会与SurfaceHolder结合使用,SurfaceHolder用于向与之关联的SurfaceView上绘图,调用SurfaceView的getHolder()方法,即可获取SurfaceView关联的SurfaceHolder。
SurfaceHolder提供了如下方法来获取Canvas对象。
(1)Canvas lockCanvas():锁定整个SurfaceView对象,获取该Surface上的Canvas。
(2)Canvas lockCanvas(Rectdirty):锁定SurfaceView上Rect划分的区域,获取该Sur- face上的Canvas。
两个方法返回的是同一个Canvas,但是第二个方法只对圈出来的区域进行刷新,Canvas绘图完成后通过unlockCanvasAndPost(canvas)方法来释放画布,提交修改。调用Surface-Holder的unlockCanvasAndPost方法之后,该方法之前所绘制的图形还处于缓冲之中,下一次lockCanvas()方法锁定的区域可能会“遮挡”它。
本例使用Android的SurfaceView实现下雨的天气动画效果。下面是具体实现过程。在Android2.3中创建应用项目:SurfaceView_Test。
先分析雨滴的实现方法。
每个雨滴其实是一条线,通过canvas.drawLine()绘制。
线(雨滴)的长度、宽度、下落速度、透明度以及位置是在一定范围内随机生成的。
每绘制一次后,改变雨滴的位置并重绘,即可实现雨滴的下落效果。
(1)在项目的源代码目录下包含四个类:MainActivity.java、BaseType.java、RainTypeImpl.java和DynamicWeatherView.java,如图7-7所示。
其中BaseType实现雨的形状,RainTypeImpl实现下雨的效果,DynamicWeatherView类继承SurfaceView,实现SurfaceHold-er.Callback的接口,在接口surfaceCreated(SurfaceHolder holder)调用线程,在线程中调用RainTypeImpl,如图7-8所示。
图7-7 项目的类文件
图7-8 项目的类关系(www.xing528.com)
可以通过Android提供给的SurfaceHolder接口访问下面的Surface。可以调用Surface-View的getHolder()来获取。
SurfaceView是有生命周期的,必须在它生命周期期间执行绘制代码,所以我们需要监听SurfaceView的状态(例如创建以及销毁),Android提供了SurfaceHolder.Callback这个接口,让我们方便地监听SurfaceView的状态。
下面了解一下SurfaceHolder.Callback接口。
绘制代码需要在surfaceCreated和surfaceDestroyed之间执行,否则无效,SurfaceHold-er.Callback的回调方法是在UI线程中执行的,绘制线程需要我们自己手动创建。
View适合与用户交互并且渲染时间不是很长的控件,因为View的绘制和用户交互都处在UI线程中。SurfaceView适合迅速更新界面或者渲染时间比较长以至于影响到用户体验的场景。
(2)类DynamicWeatherView继承自SurfaceView,为了监听SurfaceView的状态,还需要实现SurfaceHolder.Callback接口,主要代码如下。
(3)类RainTypeImpl实现下雨效果的主要代码如下。
(4)主Activity对应的布局文件activity_main.xml的代码如下。
(5)BaseType类是一个抽象基类,实现了DynamicWeatherView.WeatherType接口,内部有一些公共方法,之后要想实现不同的天气类型,只需要继承BaseType类重写相关方法即可。
(6)项目执行结果如图7-9所示。
图7-9 项目执行结果
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。