美文网首页
SurfaceView透明且不覆盖Android原生View?

SurfaceView透明且不覆盖Android原生View?

作者: youthyJ | 来源:发表于2022-03-14 18:42 被阅读0次

    引子

    最近有项目开始使用SurfaceView, 这个View跟Android中其他的View有很大的不同, 所以在使用的时候遇到了一些问题, 首当其冲就是它的背景问题.

    在我的项目中, 我希望实现如下的效果:

    视图层级:

    1. 原生View
    2. SurfaceView
    3. Activity背景

    因为希望透过SurfaceView我能看到Activity的背景, 所以我把SurfaceView的像素设置为半透明:

    surfaceView.holder.setFormat(PixelFormat.TRANSPARENT)
    

    同时为了不挡住原生View, 我把SurfaceView的层级调低:

    surfaceView.setZOrderOnTop(false)
    

    然后满心期待视图能够如我所愿的显示.

    如果你有过类似的经历, 你一定会大失所望...
    因为运行起来之后你会看到一片黑漆漆的背景...

    这是为什么呢?
    根据官方的说法, SurfaceView实际上会穿透Activity的背景, 就像在上面凿了个洞(the SurfaceView punches a hole in its window to allow its surface to be displayed. ), 然后因为Activity的Window不是透明的, 导致不能透过这洞看到后面的东西, 所以就显示成黑色的了.

    这个问题一直困扰了我很久, 在网上搜索之后发现很多人建议使用TextureView来替代SurfaceView, 但是说实话, TextureView总感觉没有SurfaceView快...

    看到这里相信你已经知道我可能有解决的方案了~

    解决方案

    既然我们知道了SurfaceView是在原来的Activity的Window上凿了个洞, 而透过这个洞后面看不到东西, 那我们在这个洞后面找一个弄一个SurfaceView补上不就行了~
    以下就是新版的层级关系:

    视图层级:

    1. 原生View
    2. 目标SurfaceView
    3. 绘制背景的SurfaceView

    关于绘制背景的SurfaceView如何绘制不是本文的讨论重点, 大家可以参考以下代码:

    svBackground.apply {
        setZOrderOnTop(false)
        setZOrderMediaOverlay(false)
        holder.setFormat(PixelFormat.OPAQUE)
        holder.addCallback(object : SurfaceHolder.Callback {
            val bgColor = 0x303030
    
            override fun surfaceCreated(holder: SurfaceHolder) {}
    
            override fun surfaceChanged(
                holder: SurfaceHolder,
                format: Int,
                width: Int,
                height: Int
            ) {
                val canvas = holder.lockCanvas()
                try {
                    canvas?.drawARGB(bgColor.alpha, bgColor.red, bgColor.green, bgColor.blue)
                } finally {
                    holder.unlockCanvasAndPost(canvas)
                }
            }
    
            override fun surfaceDestroyed(holder: SurfaceHolder) {}
    
        })
    }
    

    同时为了让我们的目标SurfaceView绘制背景的SurfaceView的层级高, 我们需要为它补充一个设置:

    surfaceView.setZOrderMediaOverlay(true)
    

    好了, 现在的话他就不是一个纯黑背景的界面了~

    相关文章

      网友评论

          本文标题:SurfaceView透明且不覆盖Android原生View?

          本文链接:https://www.haomeiwen.com/subject/aolsdrtx.html