问题分析
通常情况下,isOutsideTouchable 设置为 false,意味着当用户点击弹窗外部时,弹窗不应被关闭。然而,在一些场景下,该属性可能不生效,导致点击外部区域时,PopupWindow 仍然会关闭。
首先我们创建popupWindow一般会设置这三个属性
1.popupWindow?.isOutsideTouchable
• 作用:
• 该属性控制是否允许点击 PopupWindow 以外的区域关闭弹窗。
• 当设置为 true 时,点击弹窗外部的区域,弹窗将会关闭。
• 当设置为 false 时,点击外部区域不会关闭 PopupWindow。
• 默认值: true,即点击外部会关闭弹窗。
• 注意: 即便设置为 false,某些设备或场景下仍可能无法完全阻止弹窗关闭。这时需要配合 setTouchInterceptor 进行手动拦截。
2. popupWindow?.isFocusable
• 作用:
• 控制 PopupWindow 是否可以获得焦点。焦点意味着弹窗能够响应键盘事件(例如返回键)。
• 如果 PopupWindow 获取了焦点,则用户在点击弹窗外部区域时,事件不会传递给其他视图(例如底部的 Activity),而是由弹窗处理。关闭键盘、触摸外部区域等操作时会根据设置来决定是否关闭 PopupWindow。
• 默认值: false,即 PopupWindow 默认不会获取焦点。
• 常见用途: 设置为 true 通常用于需要用户进行输入的弹窗(例如弹出的对话框),确保键盘或返回键的事件被弹窗处理。
3. popupWindow?.isTouchable
• 作用:
• 控制 PopupWindow 是否可以响应触摸事件。
• 设置为 true 时,PopupWindow 可以被触摸,也能和其中的视图进行交互(例如点击按钮)。
• 设置为 false 时,PopupWindow 不会响应任何触摸事件,类似于一个仅显示的视图,用户无法通过触摸进行交互。
• 默认值: true,即弹窗默认可以响应触摸事件。
但是发现在设置了isOutsideTouchable后,PopupWindow 仍然会关闭,目前isOutsideTouchable 不管true还是false 设置后,点击popupWindow外的区域和点击back键都会关闭,所以如果想要阻止点击popupWindow以外区域关闭,则需要将目前isOutsideTouchable设置为false的同时也要将 isFocusable 设置为false,就比较尴尬,isFocusable设置false后PopupWindow无法获得焦点,那比如我们PopupWindow里面有EditText就会发生无法获取焦点等系列问题
这里使用 setTouchInterceptor允许我们拦截并处理触摸事件。在这里可以通过该方法来手动处理点击事件,确保当 isOutsideTouchable 设置为 false 时,外部的点击不会关闭 PopupWindow。
解释
1. setTouchInterceptor:拦截并处理触摸事件。在这个回调中,我们判断是否需要处理点击事件。
2. dispatchTouchEvent:如果 isOutsideTouchable 被设置为 false,我们手动将点击事件分发到 PopupWindow 的内容视图中,以确保点击事件不会关闭 PopupWindow。
3. 返回值:通过返回 popupWindow?.isFocusable == true && popupWindow?.isOutsideTouchable == false,确保在焦点存在且 isOutsideTouchable 为 false 时,拦截外部的点击事件。