Android 11/12中如何让悬浮图片穿透触摸事件?
解决Android 11/12悬浮窗触摸穿透问题
针对Android 11和12版本中悬浮图片无法让触摸事件穿透到底层的问题,可通过以下代码修改解决:
1. 补充WindowManager.LayoutParams的Flags
在原有flags基础上添加WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,该标记会让悬浮窗完全不接收触摸事件,直接将事件传递给底层界面。修改后的flags定义如下:
val flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
2. 明确禁用视图的触摸交互能力
在Android 11/12的系统逻辑下,明确设置视图的交互属性可避免系统默认的触摸拦截。创建overlayView时补充以下配置:
val overlayView = ImageView(this).apply { // 禁用视图的触摸、焦点能力 isClickable = false isFocusable = false isFocusableInTouchMode = false // 保留原有Glide加载代码 Glide.with(this@BrokenServiceClass) .load(imageUri) .into(this) }
3. 移除冗余触摸监听
既然已通过flags和视图属性禁用了触摸事件接收,原有的touchInterceptor触摸监听可直接移除,减少不必要的代码。
修改后的完整函数
private fun showImageOverlay(imageUri: Uri) { removeImageOverlay() val type: Int = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { WindowManager.LayoutParams.TYPE_SYSTEM_ALERT } else { WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY } val flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE val layoutParams = WindowManager.LayoutParams( WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, type, flags, PixelFormat.TRANSLUCENT ) val overlayView = ImageView(this).apply { isClickable = false isFocusable = false isFocusableInTouchMode = false Glide.with(this@BrokenServiceClass) .load(imageUri) .into(this) } windowManager?.addView(overlayView, layoutParams) overlayView.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener { override fun onViewAttachedToWindow(v: View) { // 视图附加逻辑保留 } override fun onViewDetachedFromWindow(v: View) { removeImageOverlay() } }) }
原理说明
Android 11(API 30)和12(API 31)对TYPE_APPLICATION_OVERLAY类型窗口的触摸事件处理逻辑做了调整,仅设置FLAG_NOT_FOCUSABLE不足以让事件完全穿透,必须配合FLAG_NOT_TOUCHABLE标记,同时明确禁用视图交互能力,才能确保触摸事件顺利传递到底层界面。
内容的提问来源于stack exchange,提问作者Hamza Malik
相关产品推荐
相关产品推荐

