main.xml与AndroidManifest.xml未作修改,不再贴出~
备注:
备注1介绍了在BallSurfaceView中获取屏幕宽度和高度的位置以及原因,详见代码。
备注2介绍了onTouchEvent方法在实际开发中的一个Bug的解决方法,详见代码。
第三步:运行程序,效果如下:
总结1:自定义SurfaceView的应用(总结内容来自网络,稍作整理修改)
1)继承SurfaceView类并实现SurfaceHolder.Callback接口
2)SurfaceHolder.Callback在底层的Surface状态发生变化的时候通知View,其接口有:
surfaceCreated(SurfaceHolderholder):当Surface第一次创建后会立即调用该方法。可以在该方法中做一些与绘制界面相关的初始化工作,一般情况下都是在新开的的线程来绘制界面。
surfaceChanged(SurfaceHolderholder, int format, int width,int height):当Surface的状态(大小和格式)发生变化的时候会调用该方法,在surfaceCreated调用后该方法数至少会被调用一次。
3)SurfaceHolder 类:用于控制surface的接口,它提供了控制surface 的大小,格式,上面的像素。
SurfaceView的getHolder()方法可以获取SurfaceHolder对象,Surface 就在SurfaceHolder对象内。虽然Surface保存了当前窗口的像
素数据,但是在使用过程中不直接和Surface打交道,而是由SurfaceHolder的 lockCanvas()方法来获取Canvas对象,通过在Canvas
上绘制内容来修改Surface中的数据。如果Surface不可编辑或则尚未创建调用该方法会返回null,在 unlockCanvas() 和 lockCanvas()
中Surface的内容是不缓存的,所以需要完全重绘Surface的内容,为了提高效率只重绘变化的部分则可以调用lockCanvas(Rectrect)
函数来指定一个rect区域,这样该区域外的内容会缓存起来。在调用lockCanvas函数获取Canvas后,SurfaceView会获取Surface的
一个同步锁直到调用unlockCanvasAndPost(Canvascanvas)函数才释放该锁,这里的同步机制保证在Surface绘制过程中不会被改变
(被摧毁、修改)等。
总结2:View与SurfaceView区别及应用场景(总结内容来自网络,稍作整理修改)
1)SurfaceView是View的子类。
2)View缺乏爽缓冲机制,当程序需要更新View上的图像时,程序必须重绘View上显示的整张图片。而SurfaceView类具有双缓冲机制。还可以通过CanvaslockCanvas(Rect dirty)锁定SurfaceView上的Rect划分的区域,获取该Surface上的局部Canvas,只更新局部Canvas,效率会高很多 。(对应的实例后面的文章会介绍)
3)本质区别:SurfaceView是在一个新起的单独线程中可以重新绘制画面,而View必须在UI的主线程中更新画面。
在UI的主线程中更新画面可能会引发问题,比如更新画面的时间过长,那么主UI线程可能会被正在绘图的方法阻塞。那么将无法响应按键,触屏等消息。
使用surfaceView 是在新的线程中更新画面,所以不会阻塞你的UI主线程。但也引发了另外一个问题,就是事件同步。比如触屏了一下,需要SurfaceView中thread处理,一般就需要有一个event queue的设计来保存touch event,涉及到线程同步,又变得比较复杂。
4)应用场景:如果程序或者游戏界面的动画元素较多,而且很多都需要通过定时器(主动更新View)来控制这些动画元素的移动,最好考虑使用SurfaceView,而不是View。
如果程序界面元素是通过按键、触摸、点击按钮(被动更新View)等控制动画元素,更新频率较低,采用View就可以。