You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现类似三星Air Command的Android全局背景模糊效果?

我完全懂你想要的效果——点击自己做的外部悬浮按钮后,整个手机屏幕的背景都能像三星Air Command那样一键模糊,而不是只能模糊自己应用内部的界面对吧?这个需求的核心是要实现系统级的全局模糊遮罩,毕竟普通的应用内模糊只能作用于自身界面,要覆盖其他应用甚至系统UI,得靠系统悬浮窗权限和全局覆盖层来实现。下面给你一步步拆解可行的解决方案:

解决方案步骤

1. 先搞定系统悬浮窗权限

要在其他应用和系统UI之上添加模糊层,必须先获取SYSTEM_ALERT_WINDOW权限,这是实现全局效果的前提。

检查权限状态

private fun hasOverlayPermission(): Boolean {
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        Settings.canDrawOverlays(this)
    } else {
        true // Android 6.0以下默认允许该权限
    }
}

引导用户授权

如果没有权限,就跳转到系统设置让用户开启:

private const val OVERLAY_PERMISSION_REQUEST_CODE = 1001

private fun requestOverlayPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        val intent = Intent(
            Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
            Uri.parse("package:$packageName")
        )
        startActivityForResult(intent, OVERLAY_PERMISSION_REQUEST_CODE)
    }
}

2. 创建全局模糊遮罩层

我们需要通过WindowManager添加一个全屏的透明View,这个View就是用来显示模糊效果的,初始状态隐藏,点击悬浮按钮时切换显示/隐藏。

配置遮罩层的Window参数

要确保这个遮罩层能覆盖整个屏幕,并且层级足够高,不会被其他应用遮挡:

private fun createBlurOverlayParams(): WindowManager.LayoutParams {
    val windowType = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        // Android 8.0及以上用这个类型
        WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
    } else {
        // 低版本用系统弹窗类型
        WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
    }
    return WindowManager.LayoutParams(
        WindowManager.LayoutParams.MATCH_PARENT,
        WindowManager.LayoutParams.MATCH_PARENT,
        windowType,
        // 不拦截触摸事件,让用户可以点击模糊层下方的内容(如果需要的话)
        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 
                or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
        PixelFormat.TRANSLUCENT
    ).apply {
        gravity = Gravity.TOP or Gravity.START
    }
}

实现模糊效果(分版本处理)

这里分两种方案,优先推荐Android 12+的原生模糊,低版本需要用截图模糊的方式:

方案A:Android 12+ 原生模糊(简单高效)

Android 12引入了原生的背景模糊API,不用截图就能实现全局模糊,性能更好:

private fun createBlurView(): View {
    val blurView = View(this)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        blurView.setBackgroundBlurRadius(20f) // 模糊半径,数值越大模糊效果越强
        // 加一层半透明黑色,让模糊效果更明显
        blurView.setBackgroundColor(Color.parseColor("#80000000"))
    }
    return blurView
}

方案B:兼容Android 11及以下(截图模糊)

如果要支持低版本,需要先截取当前屏幕的截图,再对截图进行模糊处理,最后把模糊后的图片作为遮罩层的背景:

private fun createBlurViewForOldVersions(): View {
    val blurView = ImageView(this)
    // 先截取屏幕截图
    val screenBitmap = takeScreenScreenshot()
    // 对截图进行模糊处理
    val blurredBitmap = blurBitmap(screenBitmap, this)
    blurView.setImageBitmap(blurredBitmap)
    return blurView
}

// 截取当前屏幕截图(Android 10+需要MEDIA_PROJECTION权限)
private fun takeScreenScreenshot(): Bitmap {
    val windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
    val display = windowManager.defaultDisplay
    val screenSize = Point()
    display.getSize(screenSize)
    val bitmap = Bitmap.createBitmap(screenSize.x, screenSize.y, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmap)
    // 注意:Android 10及以上截取屏幕需要MEDIA_PROJECTION权限,需要额外引导用户授权
    canvas.drawBitmap(bitmap, 0f, 0f, null)
    return bitmap
}

// 用RenderScript实现Bitmap模糊
private fun blurBitmap(sourceBitmap: Bitmap, context: Context): Bitmap {
    val rs = RenderScript.create(context)
    val inputAllocation = Allocation.createFromBitmap(rs, sourceBitmap)
    val outputAllocation = Allocation.createTyped(rs, inputAllocation.type)
    val blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs))
    
    blurScript.setRadius(20f)
    blurScript.setInput(inputAllocation)
    blurScript.forEach(outputAllocation)
    
    outputAllocation.copyTo(sourceBitmap)
    rs.destroy()
    return sourceBitmap
}

注意:Android 10及以上截取屏幕需要MEDIA_PROJECTION权限,这一步需要单独引导用户授权,流程会比原生模糊复杂一些,所以如果你的目标版本是Android 12+,优先用方案A。

3. 绑定悬浮按钮的点击逻辑

最后在你的悬浮按钮点击事件里,控制模糊遮罩层的显示和隐藏:

private lateinit var windowManager: WindowManager
private lateinit var blurOverlay: View
private var isBlurVisible = false

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
    
    // 根据系统版本创建对应的模糊View
    blurOverlay = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        createBlurView()
    } else {
        createBlurViewForOldVersions()
    }
    
    // 假设你已经有了悬浮按钮的创建代码,这里绑定点击事件
    val floatButton = createYourFloatButton()
    floatButton.setOnClickListener {
        if (isBlurVisible) {
            // 隐藏模糊层
            windowManager.removeView(blurOverlay)
        } else {
            // 显示模糊层
            windowManager.addView(blurOverlay, createBlurOverlayParams())
        }
        isBlurVisible = !isBlurVisible
    }
}

// 这里替换成你自己的悬浮按钮创建逻辑
private fun createYourFloatButton(): View {
    val button = Button(this)
    button.text = "模糊屏幕"
    // 配置悬浮按钮的Window参数...
    return button
}

一些关键注意事项

  • 权限兼容性:部分国产厂商(比如小米、华为)会对悬浮窗权限做额外限制,可能需要引导用户去系统设置的“应用权限”里手动开启。
  • 性能优化:截图模糊会消耗较多系统资源,尽量降低模糊半径,或者对截图进行缩小处理后再模糊。
  • 交互逻辑:如果需要用户点击模糊层就关闭模糊效果,可以给blurOverlay添加点击监听,在点击时移除遮罩层。

内容的提问来源于stack exchange,提问作者shahid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:10:25