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
相关产品推荐
相关产品推荐

