一、前言
PopupWindow 实现的功能和 Dialog 基本一样,都是弹出对话框,给用户提示和反馈操作。相比较 Dialog,PopupWindow 没有默认的对话框,两者各有优缺点。PopupWindow 更适合自定义对话框。
二、基本使用
使用起来比较简单,只要实现几个方法就可以弹出一个对话框。
- 1.实现一个简单弹出对话框,默认无阴影,点击外部不消失

private fun showSimplePw(center: Int) {//默认整个对话框窗体没有阴影//这种初始化的方法,默认点击外部区域对话框可以消失(主要是最后一个参数是 true)val contentView = layoutInflater.inflate(R.layout.pw_center, null)val popup = PopupWindow(contentView,ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT,true)//第二个参数控制显示的位置,后面两个参数控制对话框偏移量popup.showAtLocation(this.window.decorView,center,0,0)contentView.tv_pw_onetitle_cancel.setOnClickListener {popup.dismiss()}}
- 实现带阴影和点击外部消失的对话框

private fun showShawSimplePw() {//设置阴影Utils.backgroundAlpha(this,0.5f)val contentView = layoutInflater.inflate(R.layout.pw_center, null)val popup = PopupWindow()popup.contentView = contentViewpopup.width = ViewGroup.LayoutParams.MATCH_PARENTpopup.height = ViewGroup.LayoutParams.WRAP_CONTENT//设置点击空白区域消失的方法popup. isOutsideTouchable = truepopup.isFocusable = truepopup.setBackgroundDrawable(ColorDrawable())popup.showAtLocation(this.window.decorView,Gravity.CENTER,0,0)contentView.tv_pw_onetitle_cancel.setOnClickListener {popup.dismiss()}popup.setOnDismissListener {//去掉阴影Utils.backgroundAlpha(this,1f)}}
阴影是通过对屏幕设置透明度实现的,实现如下:
/*** 设置添加屏幕的背景透明度* @param bgAlpha*/fun backgroundAlpha(context: Activity,bgAlpha: Float) {val lp: WindowManager.LayoutParams = context.window.attributeslp.alpha = bgAlpha //0.0-1.0context.window.attributes = lp}
- 3.实现菜单样式对话框,默认在 View 的下方

val contentView = layoutInflater.inflate(R.layout.pw_menu, null)val popup = PopupWindow(contentView,ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT, true)//对整个 popupwindow 设置背景popup.showAsDropDown(btn_popup_menu)
- 点击对话框外部区域是否消失
如果想实现可以消失,第一种方法是在 PopupWindow 构造方法里设置 true, 示例:
PopupWindow(contentView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true)
最后一个参数设置为 true。如果没有使用这种方式初始化,还有一种方法,如下:
popup. isOutsideTouchable = true
popup.isFocusable = true
popup.setBackgroundDrawable(ColorDrawable())
三、实现阴影的方法
每个弹出对话框我都加了动画效果,PopupWindow 添加动画效果很简单,在 xml 中写好需要的动画文件,在 style 中引入动画,最后在使用 PopupWindow 示例设置动画就可以了,
示例如下:
popup.animationStyle = R.style.AnimFadeCenter
我找了很多方法,相对来说效果比较好的方法如下,Gif 图效果不是很好,真机效果更好。
- 通过设置 View 背景的方法
效果图:
这种方法阴影也有渐变动画效果,配合上对话框自身的渐变动画,效果还不错,有一个小的缺点就是在有些机型上,顶部的状态栏无法被阴影覆盖。不过这个影响不是很大。
- 通过对整个屏幕设置渐变度
效果图:
设置渐变的方法:
/*** 设置添加屏幕的背景透明度* @param bgAlpha*/fun setScreenAlpha(context: Activity, bgAlpha: Float) {val lp: WindowManager.LayoutParams = context.window.attributeslp.alpha = bgAlpha //0.0-1.0context.window.attributes = lp}
设置渐变背身是没有动画效果的,可以自己加上动画效果,配合对话框的动画,效果整体上不错,没有状态栏无法覆盖的缺陷。
- 通过设置dimAmount
效果图:
这个方法必须放在对话框显示以后设置才会生效。方法如下:
fun setScreenAlpha(context: Context, pp: PopupWindow, dimAmount: Float) {val decorView: View? = getDecorView(pp)decorView?.let {val p = decorView.layoutParams as WindowManager.LayoutParamsp.flags = p.flags or WindowManager.LayoutParams.FLAG_DIM_BEHINDp.dimAmount = dimAmount//modifyWindowLayoutParams(p)(context.getSystemService(Context.WINDOW_SERVICE) as WindowManager).updateViewLayout(decorView, p)}}private fun getDecorView(pp: PopupWindow): View? {var decorView: View? = nulltry {decorView = if (pp.background == null) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {pp.contentView.parent as View} else {pp.contentView}} else {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {pp.contentView.parent.parent as View} else {pp.contentView.parent as View}}} catch (ignore: Exception) {}return decorView}
参考:
亲,还在为PopupWindow烦恼吗?
Android PopupWindow详解
