一句话总结:
PopupWindow
是 "灵活小浮窗" (位置随意定,不打断操作),Dialog
是 "正式弹窗" (必须处理,背后变暗)------ 前者像便利贴,后者像合同签字!
一、核心区别表
特性 | PopupWindow | Dialog |
---|---|---|
显示位置 | 可自由定位(如锚定到某个View下方) | 默认居中,不可自定义位置 |
交互模式 | 非模态(默认不拦截背后点击) | 模态(必须处理,背后不可操作) |
焦点控制 | 默认无焦点,需手动设置 setFocusable(true) |
自动获取焦点 |
样式灵活性 | 高度自定义(任意布局) | 受系统主题限制,但提供标准类型(如Alert) |
生命周期 | 需手动 dismiss() |
可通过按钮自动关闭 |
背景变暗 | 需手动添加遮罩(如 setBackgroundDrawable ) |
自带背景变暗效果(可通过主题调整) |
二、适用场景(该用谁?)
1. PopupWindow 适用场景
- 下拉菜单:点击按钮弹出选项列表,锚定在按钮下方。
- 提示气泡:在某个元素旁显示临时说明。
- 自定义浮动操作栏:如长按图片后的编辑工具栏。
代码示例(锚定显示):
scss
scss
代码解读
复制代码
val popup = PopupWindow(view, width, height)
popup.showAsDropDown(anchorView) // 锚定到某个View下方
2. Dialog 适用场景
- 确认对话框:删除前的二次确认。
- 登录/表单填写:需要用户输入信息。
- 系统级提示:权限申请、错误提示。
代码示例(标准AlertDialog):
javascript
javascript
代码解读
复制代码
AlertDialog.Builder(context)
.setTitle("确认删除")
.setMessage("确定要删除这条数据吗?")
.setPositiveButton("确定") { dialog, _ ->
// 执行删除
dialog.dismiss()
}
.setNegativeButton("取消", null)
.show()
三、避坑指南(别用错!)
1. PopupWindow 常见坑
- 点击外部不消失 :需手动设置
setOutsideTouchable(true)
和背景。 - 位置计算错误 :使用
showAtLocation()
时注意屏幕坐标系。 - 内存泄漏 :在
onDestroy()
中调用dismiss()
,避免持有Activity引用。
2. Dialog 常见坑
- 主题兼容性 :不同系统版本样式差异,建议用
AppCompatDialog
。 - 生命周期处理 :旋转屏幕时可能重建,需用
DialogFragment
管理。 - 阻塞UI线程:避免在Dialog显示时执行耗时操作。
四、高级技巧
1. PopupWindow 添加动画
ini
ini
代码解读
复制代码
popup.animationStyle = R.style.PopupAnimation
styles.xml
xml
xml
代码解读
复制代码
<style name="PopupAnimation">
<item name="android:windowEnterAnimation">@anim/slide_in_top</item>
<item name="android:windowExitAnimation">@anim/slide_out_top</item>
</style>
2. Dialog 自定义布局
scss
scss
代码解读
复制代码
val dialog = Dialog(context)
dialog.setContentView(R.layout.custom_dialog)
dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) // 透明背景
五、总结口诀
PopupWindow 灵活飘,位置随意样式俏
非模态,轻打扰,下拉菜单最可靠
Dialog 正式模态框,居中变暗不可逃
确认表单必须选,系统主题要调好!