一、前言
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 = contentView
popup.width = ViewGroup.LayoutParams.MATCH_PARENT
popup.height = ViewGroup.LayoutParams.WRAP_CONTENT
//设置点击空白区域消失的方法
popup. isOutsideTouchable = true
popup.isFocusable = true
popup.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.attributes
lp.alpha = bgAlpha //0.0-1.0
context.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.attributes
lp.alpha = bgAlpha //0.0-1.0
context.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.LayoutParams
p.flags = p.flags or WindowManager.LayoutParams.FLAG_DIM_BEHIND
p.dimAmount = dimAmount
//modifyWindowLayoutParams(p)
(context.getSystemService(Context.WINDOW_SERVICE) as WindowManager)
.updateViewLayout(decorView, p)
}
}
private fun getDecorView(pp: PopupWindow): View? {
var decorView: View? = null
try {
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详解