SurfaceView

一、SurfaceView:

(一)、SurfaceView介绍:

1、前言:

        在Android系统中,有一种特殊的视图,称为SurfaceView,它拥有独立的绘图表面,即它不与其宿主窗口共享同一个绘图表面。由于拥有独立的绘图表面,因此SurfaceView的UI就可以在一个独立的线程中进行行绘制。又由于不占用主线程资源,SurfaceView一方面可以实现复杂而高效的UI另一方面又不会导致用户输入得不到及时响应

 

2、定义:

  • Surface——表面,这个概念在 图形编程中常常被提到。基本上我们可以把它当作显存的一个映射写入到Surface 的内容 可以被直接复制到显存从而显示出来,这使得显示速度非常快
  • 可以直接从内存或者DMA直接存储器访问(Direct Memory Access)】等硬件接口取得图像数据,是个非常重要的绘图容器。
  • 它的特性是:可以在主线程之外的线程中向屏幕绘图。这样可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度。当界面的动画元素较多,而且很多都需要通过定时器来控制这些动画元素的移动,就考虑使用SurfaceView。游戏开发中多用到SurfaceView,游戏中的背景、人物、动画等等尽量在画布canvas中画出。

3、View绘图机制的缺陷:

  • View缺乏双缓冲机制
  • 当程序需要更新View上的图像时,程序必须重绘View上显示的整张图片;
  • 新线程无法直接更新View组件。

    View存在上述缺陷,所以通过自定义View来绘图,尤其是游戏中的绘图,性能不好。一般推荐使用SurfaceView。

    SurfaceView有以下三个特点

A. 具有独立的绘图表面

B. 需要在宿主窗口上挖一个洞来显示自己

C. 它的UI绘制可以在独立的线程中进行,这样就可以进行复杂的UI绘制,并且不会影响应用程序的主线程响应用户输入。

4、使用SurfaceView的必要性:

        普通的Android控件,例如TextView、Button和CheckBox等,它们都是将自己的UI绘制在宿主窗口的绘图表面之上,这意味着它们的UI是在应用程序的主线程中进行绘制的。由于应用程序的主线程除了要绘制UI之外,还需要及时地响应用户输入,否则的话,系统就会认为应用程序没有响应了,因此就会弹出一个ANR对话框出来。对于一些游戏画面,或者摄像头预览视频播放来说,它们的UI都比较复杂,而且要求能够进行高效的绘制,因此,它们的UI就不适合在应用程序的主线程中进行绘制。这时候就必须要给那些需要复杂而高效UI的视图生成一个独立的绘图表面,以及使用一个独立的线程来绘制这些视图的UI。

 

5、SurfaceView的API介绍:

        Provides a dedicated drawing surface embedded inside of a view hierarchy. You can control the format of this surface and, if you like, its size; the SurfaceView takes care of placing the surface at the correct location on the screen

        The surface is Z ordered so that it is behind the window holding its SurfaceView; the SurfaceView punches a hole in its window to allow its surface to be displayed. The view hierarchy will take care of correctly compositing with the Surface any siblings of the SurfaceView that would normally appear on top of it. This can be used to place overlays such as buttons on top of the Surface, though note however that it can have an impact on performance since a full alpha-blended composite will be performed each time the Surface changes.

        Access to the underlying surface is provided via the SurfaceHolder interface, which can be retrieved by calling getHolder().

        The Surface will be created for you while the SurfaceView's window is visible; you should implement surfaceCreated(SurfaceHolder) and surfaceDestroyed(SurfaceHolder) to discover when the Surface is created and destroyed as the window is shown and hidden.

        One of the purposes of this class is to provide a surface in which a secondary thread can render in to the screen. If you are going to use it this way, you need to be aware of some threading semantics:

  • All SurfaceView and SurfaceHolder.Callback methods will be called from the thread running the SurfaceView's window (typically the main thread of the application). They thus need to correctly synchronize with any state that is also touched by the drawing thread.
  • You must ensure that the drawing thread only touches the underlying Surface while it is valid -- between SurfaceHolder.Callback.surfaceCreated() and SurfaceHolder.Callback.surfaceDestroyed(). 

 

6、SurfaceView的中文API介绍:

        SurfaceView是视图(View)的继承类,这个视图里内嵌了一个专门用于绘制的Surface。你可以控制这个Surface的格式和尺寸。Surfaceview控制这个Surface的绘制位置。

        surface是纵深排序(Z-ordered)的,这表明它总在自己所在窗口的后面。surfaceview提供了一个可见区域,只有在这个可见区域内 的surface部分内容才可见,可见区域外的部分不可见。surface的排版显示受到视图层级关系的影响,它的兄弟视图结点会在顶端显示。这意味着 surface的内容会被它的兄弟视图遮挡,这一特性可以用来放置遮盖物(overlays)(例如,文本和按钮等控件)。注意,如果surface上面 有透明控件,那么它的每次变化都会引起框架重新计算它和顶层控件的透明效果,这会影响性能。

        你可以通过SurfaceHolder接口访问这个surface,getHolder()方法可以得到这个接口。

        surfaceview变得可见时,surface被创建;surfaceview隐藏前,surface被销毁。这样能节省资源。如果你要查看 surface被创建和销毁的时机,可以重载surfaceCreated(SurfaceHolder)和 surfaceDestroyed(SurfaceHolder)。

        surfaceview的核心在于提供了两个线程:UI线程渲染线程。这里应注意:

        1> 所有SurfaceViewSurfaceHolder.Callback的方法都应该在UI线程里调用,一般来说就是应用程序主线程。渲染线程所要访问的各种变量应该作同步处理。

        2> 由于surface可能被销毁,它只在SurfaceHolder.Callback.surfaceCreated()和 SurfaceHolder.Callback.surfaceDestroyed()之间有效,所以要确保渲染线程访问的是合法有效的surface。

 

(二)、实现SurfaceView:

1、首先继承SurfaceView并实现SurfaceHolder.Callback接口

       使用接口的原因:因为使用SurfaceView 有一个原则,所有的绘图工作必须得在Surface 被创建之后才能开始,而在Surface 被销毁之前必须结束。所以Callback 中的surfaceCreated() surfaceDestroyed() 就成了绘图处理代码的边界。 

 

2、SurfaceHolder.Callback接口需要重写的方法:

 (1)public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){}

  //在surface的大小发生改变时激发

 (2)public void surfaceCreated(SurfaceHolder holder){}

  //在创建时激发,一般在这里调用画图的线程。

 (3)public void surfaceDestroyed(SurfaceHolder holder) {}

  //销毁时激发,一般在这里将画图的线程停止、释放。

 

3、实现步骤:【重要

  •  SurfaceView.getHolder()获得SurfaceHolder对象 ---->
  • SurfaceHolder.addCallback(callback)添加回调方法---->
  • 实现SurfaceHolder.Callback接口 ,重写其中的方法---->
  • SurfaceHolder.lockCanvas()获得Canvas对象并锁定画布---->
  •  Canvas绘画 ---->
  • SurfaceHolder.unlockCanvasAndPost(Canvas canvas)结束锁定画图,并提交改变,将图形显示。

 

4、SurfaceHolder:

        SurfaceView与SurfaceHolder结合使用。SurfaceHolder用于向与之关联的SurfaceView上绘图。调用SurfaceView的getHolder()方法即可获取SurfaceHolder。

        用到了一个类SurfaceHolder,可以把它当成surface的控制器,用来操纵surface。处理它的Canvas上画的效果和动画,控制表面,大小,像素等。

        几个需要注意的方法:

(1)、abstract void addCallback(SurfaceHolder.Callback callback);

给SurfaceView当前的持有者一个回调对象。

(2)、abstract Canvas lockCanvas();

锁定画布,一般在锁定后就可以通过其返回的画布对象Canvas,在其上面画图等操作了。

(3)、abstract Canvas lockCanvas(Rect dirty);

锁定画布的某个区域进行画图等..因为画完图后,会调用下面的unlockCanvasAndPost来改变显示内容。

相对部分内存要求比较高的游戏来说,可以不用重画dirty外的其它区域的像素,只对Rect所圈出来的区域进行更新,通过这种方式可以提高画面的更新速度

(4)、abstract void unlockCanvasAndPost(Canvas canvas);

结束锁定画图,并提交改变。

 

二、绘图类及绘制图像:Paint、Canvas、Bitmap、BitmapFactory类。

(一)、Paint类:

        代表画笔,用来描述图形的颜色和风格,如:颜色、透明度、文字大小等等。

1、setARGB(int a , int  r , int  g , int  b)  :  参数值在0-255之间

2、setColor(int color)  :  Color.rgb(int  r , int  g , int  b)

3、setAlpha(int a) :  透明度0-255之间

4、setAntiAlias(boolean a ) : 是否使用抗锯齿功能,但是如果使用使绘图速度变慢

5、setShader(Shader shader) : 用于设置渐变,可以使用LinearGradient(线性渐变) , RadialGradient (径向渐变), SweepGradient(角度渐变)

6、setTextAlign(Paint.Align  align)  :  用于设置绘制文本的对齐方式。Align.CENTER , Align.LEFT , Align.RIGHT

7、setTextSize(float  textSize)  :  用于设置绘制文本的文字大小

8、setStrokeWidth(float width) : 设置笔触宽度

 

(二)、Canvas类:

        代表画布,通过该类的方法,可以绘制各种图形(矩形、圆形、线条)。

1、drawArc()  :  绘制弧   useCenter为true或者false

2、drawCircle()  :  绘制圆形   

3、drawLine() :  绘制一条线

4、drawLines() :  绘制多条线

5、drawOval() :  绘制椭圆

6、drawPoint()  :  绘制一个点   

7、drawPoints() :  绘制多个点

8、drawRect() :  绘制矩形

9、drawRoundRect() :  绘制圆角矩形

10、drawText() :  绘制文本

11、drawBitmap() :  绘制图片

12、drawPath()  :   绘制路径

13、drawTextOnPath()  :   绘制路径

 

(三)、Path类绘制路径:

A、创建路径:通过android.graphics.Path类来实现。

1、addArc()      添加弧形路径

2、addCircle()    添加圆形路径

3、addOval()     添加椭圆形路径

4、addRect()     添加矩形路径

5、addRoundRect()    添加圆角矩形路径

6、moveTo()    设置绘制直线的起始点

7、lineTo()     绘制直线

8、quadTo()   绘制线段轨迹

9、close()   闭合路径

 

B、将定义好的路径绘制在画布上:

1、drawPath()  :   绘制路径

2、drawTextOnPath()  :   沿着指定路径绘制字符串

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值