RE: 从零开始的车载Android HMI(三) - SurfaceView

本文详细介绍了车载应用开发中SurfaceView的使用,包括其概念、应用场景、基础用法、双缓冲机制及其注意事项,为初学者提供实用的开发指导。

1.前言

从零开始的车载Android HMI是一个系列性的文章,目的在于展示一些在Android手机应用开中不常用,但是在车载应用开发中较为常用的一系列Android HMI 组件,希望能够帮助初入车载应用开发的同学了解车载应用开发过程中常用的各种UI 组件。

RE: 从零开始的车载Android HMI(一) - Lottie

RE: 从零开始的车载Android HMI(二) - Widget
在这里插入图片描述

本文参考资料:

《Android自定义控件开发入门与实战》 - 启舰

Understanding Canvas and Surface concepts

Surface | Android Developers

2.SurfaceView 简介

相信每一个Android初学者在自学Android编程时都使用过VideoView来播放视频,当打开VideoView的源码时,会发现VideoView并不是直接继承自我们常用的ViewGroup或是View,它实际上继承自一种更特殊的View - SurfaceView

2.1.SurfaceView 是什么

简单来说,SurfaceView就是一个嵌入了Surface的特殊View,Surface中有一个独立的画布Canvas用于绘制内容,SurfaceView本质上是这个Surface的容器,用于控制Surface的格式、尺寸等基础信息。

SurfaceView显示内容时,会在Window上挖一个洞,SurfaceView绘制的内容显示在这个洞里,其他的View继续显示在Window上。

2.2.SurfaceView 应用场景

SurfaceView的出现并不是为了取代View,当界面绘制需要频繁刷新,或刷新时需要处理的数据量较大时,就应该考虑使用SurfaceView,例如:视频播放、展示摄像头数据。在车载应用开发中,我们通常使用SurfaceView展示Camera的数据,例如 泊车雷达 等应用。如果需要对来自Camera的数据进行二次处理后再展示,应该使用TextureView

3.SurfaceView 基础用法

接下来我们写一个简单绘的图板,来看一下SurfaceView的基础用法是怎样的。

1.创建一个继承自SurfaceView的自定义View,并初始化Paint、Path

init {
    paint = Paint(Paint.ANTI_ALIAS_FLAG)
    paint.color = Color.BLUE
paint.style = Paint.Style.STROKE
paint.strokeWidth = 5f
    path = Path()
}

2.获取SurfaceHolder,并监听Surface生命周期

init {
    ...
    // 为了代码的可读性,这里并没有使用Kotlin的简写
surfaceHolder = getHolder()
    surfaceHolder?.addCallback(this)
}

override fun surfaceCreated(holder: SurfaceHolder) {
    flag = true
    drawCanvas()
}

override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {

}

override fun surfaceDestroyed(holder: SurfaceHolder) {
    flag = false
}

SurfaceHolder从名字上就能看出,他是Surface的持有对象,必须通过它才能获取到绘图所必须的画布。下一节会详细介绍。

3.监听手势

override fun onTouchEvent(event: MotionEvent?): Boolean {
    when (event?.action) {
        MotionEvent.ACTION_DOWN -> {
            path.moveTo(event.x, event.y)
            return true
        }
        MotionEvent.ACTION_MOVE -> {
            path.lineTo(event.x, event.y)
        }
    }
    return super.onTouchEvent(event)
}

通过onTouchEvent监听到屏幕上的手势移动,并将轨迹保存在Path中。

4.在子线程中将轨迹绘制到画布上

private fun drawCanvas() {
    Thread {
while (flag) {
            val canvas = surfaceHolder.lockCanvas()
            canvas.drawPath(path, paint)
            surfaceHolder.unlockCanvasAndPost(canvas)
        }
    } .start()
}

在这一步中,通过SurfaceHolder获取到SurfaceView自带的缓冲画布,并对这个画布加锁surfaceHolder.lockCanvas()

在绘制完成后,将缓冲画布释放,并将画布的内容更新到主线程的画布上surfaceHolder.unlockCanvasAndPost(canvas),这样缓冲画布的内容就显示到屏幕上了。

完整的源码如下所示:

class CustomSurfaceView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
) : SurfaceView(context, attrs), SurfaceHolder.Callback {

    private val paint: Paint
    private val path: Path
    private val surfaceHolder: SurfaceHolder
    private var flag: Bo
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值