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

Android如何实现PopupWindow仅在触摸释放时消失、长按期间不关闭?

解决方法

问题原理

你当前设置的focusable=true会让PopupWindow启用默认外部触摸关闭逻辑,该逻辑在触摸按下(ACTION_DOWN)阶段就会触发dismiss,所以任意点击/长按外部都会立刻关闭弹窗。

修改步骤

  1. 先禁用PopupWindow默认的外部关闭逻辑,改为自行处理触摸事件
  2. 监听全局触摸事件,仅在触摸抬起(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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 01:54:04