今天在掘金上看了个文章,写的实现QQ右上角点击弹出菜单,想着自己好像都没用过PopupWindow,马上撸起袖子开搞。记录下实现的过程中一些需要注意的地方,方便以后参考。
实现一个简单的PopupWindow
从官方文档里我们可以看到PopupWindow有很多构造方法,但是无论选择哪个构造方法最后都可以通过PopupWindow的其他方法达到同样的效果,经常使用的有
PopupWindow(int width, int height)
PopupWindow(View contentView, int width, int height)
PopupWindow(View contentView, int width, int height, boolean focusable)
其中contentView就是详细的内容,可以写在XML文件中,再通过View.infalte方法转换成View对象。
设置好popupWindow的各个属性后接下来就是显示PopupWindow了。
文档中有几个显示popupWindow的方法
-
void showAsDropDown(View anchor)
将popupWindow显示在anchor的左下方,如果屏幕上空间不够的话,系统会试着给popupWindow找一个可滑动的父View。如果没有可滑动的父View,popupWindow的 void showAsDropDown(View anchor, int xoff, int yoff, int gravity)
-
void showAsDropDown(View anchor, int xoff, int yoff)
在默认左下方的基础上加上x和y的偏移量显示PopupWindow -
void showAtLocation(View parent, int gravity, int x, int y)
显示在一个具体的位置上
点击空白处消失
经常有这样的需求,需要我们在打开一个PopupWindow后点击非菜单栏区域可以让PopupWindow消失。
为了实现这样的功能,首先我们要将popupWindow的setFocusable设置为true。这样popupWindow才能处理我们的点击事件,popupWindow内的元素也才能响应各自的点击事件。
备注:网络上找到的教程里说需要给popupWindow设置一个backgroundDrawable,否则会有莫名其妙的bug。但我在实践的时候没发现什么影响,暂做记录。另外setOutsideTouchable这个方法设置为false好像也没什么影响。。
显示PopupWindow时其余区域背景变暗
这也是经常需要实现的功能,网上检索了一下资料,有几种实现方法,暂时只尝试了比较简单的一种,将Window的背景变暗,这个方法理解起来也比较容易,具体代码
private void setBackgroundAlpha(float alpha) {
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.alpha = alpha;
getWindow().setAttributes(lp);
}
在使用时只需要写一行代码setBackgroundAlpha(0.6f)
就可以实现背景变暗的效果,效果如下图
但是仅这样我们会发现当我们点击空白区域后popupwindow消失了,但是背景还是暗的,这是因为我们没有将window的背景恢复成原来的透明度。
找了一下文档发现有个setOnDimissListener的方法,也就是说我们可以设置监听器来监听popupwindow消失的时间,在监听器里设置setBackgroundAlpha(1f)
。这样当popupwindow消失的时候,空白区域也恢复了原来的颜色。
PopupWindow内的列表响应点击事件
这个比较简单了,在设置contentView的时候,通过findViewById来获取contentView内的View实例,再设置相应的View.OnClickListener就可以了。当然这一切的前提还是一个setFocusable(true),如果没有这个属性的保证,PopupWindow内的东西是无法处理相应的事件的。
PopupWindow和Dialog的区别
PopupWindow和Dialog一个很重要的区别是在于是否是线程阻塞的。
PopupWindow是线程阻塞的,也就是说:当PopupWindow弹出后,程序是一直阻塞的,只有当PopupWindow执行了dimiss方法后,程序才会继续执行。
而AlertDialog是非阻塞式的对话框,后台还可以做其他事情。
另外还有一些显示效果的不同,如:
- Dialog默认有标题,PopupWindow没有
- PopupWindow显示前要设置宽高,而Dialog不用
- PopupWindow默认不响应物理的返回按键,除非设置了setFocusable(true)属性,而在点击返回按键后,Dialog会消失
最后
PopupWindow还可以设置动画啥的,暂时还没有学习到,本文只是一个简单的使用。这篇笔记是赶在元旦前写的第一篇学习笔记,希望新的一年能够多写东西,多成长一点。