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

Android悬浮窗布局:实现栏间可穿透点击的空白区域

实现悬浮栏布局并允许空白区域穿透点击

要做这种悬浮在其他应用上层、中间空白可点击下层应用的布局,核心是让根布局不拦截触摸事件,仅让两个按钮栏消费点击,结合ConstraintLayout的灵活约束来实现,步骤如下:

1. 先搞定悬浮窗权限

悬浮应用必须申请SYSTEM_ALERT_WINDOW权限,Android 6.0+需要引导用户手动开启「显示在其他应用上层」权限,这是实现基础,没权限无法完成悬浮效果。

2. 布局实现(ConstraintLayout方案)

用ConstraintLayout作为根容器,它能精准定位两个按钮栏,同时让空白区域自然穿透。关键是属性设置:

  • 根ConstraintLayout:android:clickable="false"、android:focusable="false",不消费任何触摸事件,让点击直接透传到下层应用
  • 两个LinearLayout按钮栏:android:clickable="true"、android:focusable="true",确保栏内按钮能响应点击,不会让点击穿透

示例布局代码

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clickable="false"
    android:focusable="false">

    <!-- 顶部居中按钮栏 -->
    <LinearLayout
        android:id="@+id/top_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:clickable="true"
        android:focusable="true"
        android:background="#80000000"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:padding="8dp">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="按钮1"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="按钮2"
            android:layout_marginLeft="8dp"/>
    </LinearLayout>

    <!-- 底部居中按钮栏 -->
    <LinearLayout
        android:id="@+id/bottom_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:clickable="true"
        android:focusable="true"
        android:background="#80000000"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:padding="8dp">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="按钮3"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="按钮4"
            android:layout_marginLeft="8dp"/>
    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

3. 悬浮窗WindowManager参数配置

在添加悬浮窗时,必须设置FLAG_NOT_TOUCH_MODAL,这个flag的作用是:悬浮窗不会拦截自身区域外的触摸事件,而自身可点击区域会正常处理事件。示例代码片段:

val windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
val params = WindowManager.LayoutParams().apply {
    type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
    } else {
        WindowManager.LayoutParams.TYPE_PHONE
    }
    flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
    width = WindowManager.LayoutParams.MATCH_PARENT
    height = WindowManager.LayoutParams.MATCH_PARENT
    format = PixelFormat.TRANSLUCENT
}

// 将布局添加到WindowManager
val view = LayoutInflater.from(this).inflate(R.layout.floating_layout, null)
windowManager.addView(view, params)

关键属性说明

  • android:clickable="false":视图不会响应点击事件,触摸事件会继续向下传递到下层应用
  • android:focusable="false":视图不会获取焦点,避免干扰下层应用的焦点处理逻辑
  • FLAG_NOT_TOUCH_MODAL:必须设置,否则悬浮窗会拦截整个屏幕的触摸事件,空白区域就无法点击到下层应用

注意事项

  • 按钮栏内的Button默认focusable为true,无需额外设置;如果是自定义View,要确保需要响应点击的View开启clickable和focusable
  • 根布局不要设置不透明背景,否则即使clickable为false,不透明背景也会拦截触摸事件

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 12:03:17