Android中毛玻璃效果的实践

问题背景:需要在一个Activity内实现一个dialog,并让dialog周围的半透明遮罩变为高斯模糊效果。正常接入组件库后,TV上面未出现高斯模糊效果

实际尝试的方案(方案1和2为Activity内直接写布局,方案3为空activity加载组件弹窗):
方案1:Activity利用

	<item name="android:windowIsTranslucent">false</item>
	<item name="android:colorBackground">@android:color/transparent</item>

可以实现模糊度效果,但是存在致命问题:Activity弹出后,MainActivity直接被透明了,看到了桌面

方案2:利用

<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">?attr/colorPrimarySurface</item> 		

可是避免方案1的问题,但是模糊度没办法做到和组件一样,只能通过调节模糊比例,做到近似效果

方案3:直接在activity内对接公共组件库dialog,目前在TV上无法实现高斯模糊效果
通过修改activity主题后,
使用方案1主题,可实现毛玻璃效果,但出现的问题与方案1一致
使用方案2主题,无毛玻璃效果

通过以上尝试,可以判断出activity对接组件dialog毛玻璃不生效,跟使用的主题有较大关系,但是首页被透明显示的问题未查到根本原因,只知道与

<item name="android:colorBackground">@android:color/transparent</item>

这个属性设置有很大关系

方案2实现方式:

    override fun onCreate(savedInstanceState: Bundle?) {
        lifecycle.addObserver(BackgroundBlurUtil(window))
        super.onCreate(savedInstanceState)
    }
class BackgroundBlurUtil(
    private var window: Window?,
    private val mBackgroundBlurRadius: Int = 20,    //窗口背景高斯模糊程度,数值越高越模糊且越消耗性能
    private val mBlurBehindRadius: Int = 20,        //窗口周边背景高斯模糊程度
    private val mDimAmountWithBlur: Float = 0f,    //根据窗口高斯模糊功能是否开启来设置窗口周边暗色的程度
): DefaultLifecycleObserver {
    override fun onCreate(owner: LifecycleOwner) {
        super.onCreate(owner)
        initBlur()
    }

    override fun onDestroy(owner: LifecycleOwner) {
        super.onDestroy(owner)
        window = null
    }

    /**
     * 更新窗口的高斯模糊效果
     */
    private fun updateWindowForBlurs() {
        //设置背景模糊程度
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            LogUtils.d("BackgroundBlurUtil", "updateWindowForBlurs")
            window?.setBackgroundBlurRadius(mBackgroundBlurRadius)
            //设置背景周边模糊程度
            window?.attributes?.blurBehindRadius = mBlurBehindRadius
            //调整背景周边昏暗的程度
            window?.setDimAmount(mDimAmountWithBlur)
            //让上面的高斯模糊效果生效
            window?.attributes = window?.attributes
        }
    }

    /**
     * 设置一个窗口视图状态监听者,监听窗口视图是否可见以便是否更新窗口模糊的状态
     */
    private fun setupWindowBlurListener(){
        val windowBlurEnabledListener = Consumer { _: Boolean? ->
            updateWindowForBlurs()
        }
        window?.decorView?.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener{
            override fun onViewAttachedToWindow(v: View) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                    window?.windowManager?.addCrossWindowBlurEnabledListener(windowBlurEnabledListener)
                }
            }

            override fun onViewDetachedFromWindow(v: View) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                    window?.windowManager?.removeCrossWindowBlurEnabledListener(windowBlurEnabledListener)
                }
            }
        })
    }
    
    private fun initBlur(){
        window?.run {
            //允许背景模糊,也可以通过样式属性R.attr#windowBlurBehindEnabled来实现
            addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND)

            // 允许背景变暗,也可以通过样式属性R.attr#backgroundDimEnabled来实现
            addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
        }
        // 高斯模糊监听
        setupWindowBlurListener()
    }
}

关于主题:
继承基础主题后,实现如下两个属性:

<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">?attr/colorPrimarySurface</item>

主题属性介绍:
windowIsTranslucent:
windowIsTranslucent 通常用于创建半透明的对话框或菜单,是控制窗口是否半透明。 设置为 true 时,窗口将是半透明的,窗口后面的内容也将是可见的。设置为 false 时,窗口将是不透明的,窗口后面的内容将不可见。
windowIsTranslucent 主题属性在 Android 4.0(API 14)及更高版本上可以生效,需要与 windowBackground 属性一起使用,windowBackground 属性用于指定窗口的背景颜色

还有另外一个方案:将windowIsTranslucent设置为false,但是设置colorBackground和windowBackground为透明,再设置布局中的背景色,但是这个方案出现了底层activity完全透明的现象,具体原因不得而知

	<item name="android:windowIsTranslucent">false</item>
	<item name="android:colorBackground">@android:color/transparent</item>

参考:
Android12窗口模糊(一)在Activity和Dialog中实现高斯模糊效果
android13 FLAG_BLUR_BEHIND 壁纸高斯模糊,毛玻璃背景方案设计

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值