Android如何实现PopupWindow仅在触摸释放时消失、长按期间不关闭?
解决方法
问题原理
你当前设置的focusable=true会让PopupWindow启用默认外部触摸关闭逻辑,该逻辑在触摸按下(ACTION_DOWN)阶段就会触发dismiss,所以任意点击/长按外部都会立刻关闭弹窗。
修改步骤
- 先禁用PopupWindow默认的外部关闭逻辑,改为自行处理触摸事件
- 监听全局触摸事件,仅在触摸抬起(ACTION_UP)且触摸区域在弹窗外部时才关闭弹窗
修改后的代码
首先是showDetails方法的修改:
private fun showDetails() { val inflater: LayoutInflater = activity?.getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater val popupView: View = inflater.inflate(R.layout.popup_tigerbuilder_details, null) popupView.findViewById<TextView>(R.id.tgrbdetdevice_name).text = device.name if (Build.VERSION.SDK_INT >= 30) { popupView.findViewById<TextView>(R.id.tgrbdetdevice_nickname).text = device.alias popupView.findViewById<TextView>(R.id.tgrbdetdevice_nickname).visibility = View.VISIBLE } popupView.findViewById<TextView>(R.id.tgrbdetdevice_mac).text = device.address // create the popup window val width: Int = LinearLayout.LayoutParams.WRAP_CONTENT val height: Int = LinearLayout.LayoutParams.WRAP_CONTENT // 无输入需求可设为false,避免抢输入法/状态栏事件,有输入框改回true即可 val focusable = false val popupWindow = PopupWindow(popupView, width, height, focusable) popupWindow.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)); popupWindow.setIgnoreCheekPress() popupWindow.animationStyle = -1 // 禁用默认外部触摸关闭逻辑 popupWindow.setOutsideTouchable(false) popupWindow.isTouchable = true // show the popup window popupWindow.showAtLocation(view?.parent as View, Gravity.CENTER, 0, 0) popupWindow.dimBehind() // 存储弹窗在屏幕中的位置数组 val popupLocation = IntArray(2) popupView.post { popupView.getLocationOnScreen(popupLocation) } // 自定义全局触摸监听 val touchListener = View.OnTouchListener { _, event -> if (event.action == MotionEvent.ACTION_UP) { val x = event.rawX.toInt() val y = event.rawY.toInt() // 判断触摸位置是否在弹窗外部 val isOutside = x < popupLocation[0] || x > popupLocation[0] + popupView.width || y < popupLocation[1] || y > popupLocation[1] + popupView.height if (isOutside) { popupWindow.dismiss() } } // 事件不拦截,交给下层视图处理原有逻辑 false } // 给Activity的DecorView添加触摸监听 val decorView = activity?.window?.decorView decorView?.setOnTouchListener(touchListener) // 弹窗关闭时移除监听,避免内存泄漏 popupWindow.setOnDismissListener { decorView?.setOnTouchListener(null) } popupView.setOnClickListener { Log.d("Fragment", it.id.toString()) } }
原有的dimBehind扩展方法不需要修改,可直接保留使用。
内容的提问来源于stack exchange,提问作者Wavpro
相关产品推荐
相关产品推荐

