如何正确获取Alert Dialog的宽高尺寸?
正确获取AlertDialog宽高的解决方案
我之前也遇到过类似的问题,这是因为AlertDialog的视图在show()调用后并不会立即完成布局绘制,所以直接获取宽高会得到0。下面是几种可靠的解决方案,以及对你遇到的其他问题的解释:
1. 使用ViewTreeObserver监听布局完成
这是最稳妥的方法,当Dialog的视图完成测量和布局后,我们就能拿到准确的宽高:
val alertDialog = AlertDialog.Builder(parent.context) .setView(R.layout.sample_layout) .create() alertDialog.show() // 监听DecorView的布局完成事件 alertDialog.window?.decorView?.viewTreeObserver?.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { override fun onGlobalLayout() { // 移除监听,避免重复触发回调 alertDialog.window?.decorView?.viewTreeObserver?.removeOnGlobalLayoutListener(this) val alertBoxHeight = alertDialog.window?.decorView?.height val alertBoxWidth = alertDialog.window?.decorView?.width // 在这里使用获取到的宽高进行定位操作 alertBoxHeight?.let { height -> alertBoxWidth?.let { width -> val windowParams = alertDialog.window?.attributes windowParams?.apply { // 示例:将Dialog定位到目标坐标的上方居中位置 x = yourTargetX - width / 2 y = yourTargetY - height alertDialog.window?.attributes = this } } } } })
2. 利用Dialog的OnShowListener结合post()
在Dialog显示后,通过post()把获取宽高的逻辑放到UI消息队列的末尾,等视图绘制完成后再执行:
val alertDialog = AlertDialog.Builder(parent.context) .setView(R.layout.sample_layout) .setOnShowListener { dialog -> val targetDialog = dialog as AlertDialog // 把任务post到消息队列,等待布局完成 targetDialog.window?.decorView?.post { val alertBoxHeight = targetDialog.window?.decorView?.height val alertBoxWidth = targetDialog.window?.decorView?.width // 这里处理宽高相关的定位逻辑 } } .create() alertDialog.show()
关于你遇到的其他问题解释
为什么
alertDialog.window?.attributes.width返回-2?
这个-2是ViewGroup.LayoutParams.WRAP_CONTENT的常量值,代表Dialog的宽度设置为自适应内容,并不是实际测量后的真实宽高。手动测量布局宽度过大的原因?
你使用View.MeasureSpec.UNSPECIFIED时,布局不会受到宽度限制,会按照自身内容的最大宽度来测量。如果要模拟Dialog的实际宽度限制,可以用View.MeasureSpec.AT_MOST,并传入屏幕的可用宽度作为上限:
val alertLayout = alertDialog.findViewById<ConstraintLayout>(R.id.parentLayout) alertLayout?.let { layout -> val displayMetrics = parent.context.resources.displayMetrics // 减去左右边距,模拟Dialog的实际宽度限制 val maxWidth = displayMetrics.widthPixels - 2 * resources.getDimensionPixelSize(R.dimen.dialog_horizontal_margin) layout.measure( View.MeasureSpec.makeMeasureSpec(maxWidth, View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) ) val measuredWidth = layout.measuredWidth val measuredHeight = layout.measuredHeight }
这样测量出来的宽度会更接近Dialog实际显示的宽度,因为考虑了屏幕边距和自适应限制。
内容的提问来源于stack exchange,提问作者Manasa Murali
相关产品推荐
相关产品推荐

