为了账号安全,请及时绑定邮箱和手机立即绑定

记一次popupwindow点击外部区域不消失问题

标签:
Java

问题描述:

最近用popupwindow实现了一个筛选的弹窗,项目在调试阶段,在我的一加5上调试是可以正常打开关闭popupwindow的,但是有用户反馈,其vivo手机点击打开弹窗之后,点击其他区域或者是手机返回键,均无效果

问题出现的原因:

根据用户的表述,应该就是popupwindow dismiss出错了,所以,我们就从dismiss这个方法开始追溯。

webp

api 27 dismiss()

从这里我们可以看到,阻止dismiss往下调用的就是开头的两个标志位,通过全文搜索发现,这两个标志位,在popupwindow弹出的情况,这里的条件均是不满足的,所以dismiss方法内部不会造成点击外部区域不消失问题。

既然dismiss函数不会阻断弹框消失的效果,那么我们就接着向上追溯,看看哪些地方调用了这个方法。通过搜索发现有个PopupDecorView的类调用到了dismiss方法。

webp

api 27 PopupDecorView节选

根据bug表述,我们首先锁定dispatchKeyEvent方法和onTouchEvent方法,popupwindow的外部点击消失,主要靠监听触摸事件并加以判断实现的,阅读者两个方法,发现均处于正常操作,并无什么异常的地方,那么我们就只能接着再往上追溯。

webp

api 27 preparePopup()

从代码中,我们发现这句mDecorView = createDecorView(mBackgroundView),这一句则是构建了DecorView,也就是说,只要调用了preparePopup这个方法,我们的decorView就会被创建,我们的触摸响应事件也是有效的。这也就是我在一加5 Android 8.0的手机上调试都是正常的原因。但是用户的手机为什么会点击外部,窗口会不消失呢?查看了用户的手机配置之后,发现用户使用的是基于Android 5.1的vivo手机,那就查看一下api 22的源码。

dimiss方法我们就不再看了,大同小异,我们接着向上追溯。搜索全文发现,有个地方有用到dismiss,那就是PopupViewContainer类,诶,和我们之前看到的api27 的类不一样耶,但是仔细看看,该类的监听触摸实现部分的实现几乎是一样的。

webp

api 22 PopupViewContainer节选

我们接着向上追溯。

webp

api 22 prepare()

我们再次回到了prepare方法,阅读代码,PopupViewContainer只有在mBackground不为空的时候才会创建,换句话说,如果mBackground为空,那么我们的PopupViewContainer就不会创建,那么触摸事件就会受到影响,那么mBackground什么时候会被赋值呢,全文搜索发现在setBackgroundDrawable()方法内被赋值,而该方法可被外部调用以及内部的构造方法,查看下构造方法。

webp

api 22 PopupWindow()

通过代码发现,默认情况下,构造方法都会调用setBackgroundDrawable(bg)方法为mBackground赋值,所以说,正常情况下,mBackground是不为空的,除非是用户强制设置进去的。但是回查自己的代码,是并没有设置mBackground为空的,那么为什么触摸事件还是会受到影响呢?结合网上查询的结果得出,在Android的某些版本,在构造方法内,是没有调用setBackgroundDrawable方法的,又或者是传递的参数为空。为了避免这个问题,我们最好是直接给PopupWindow设置一个背景以兼容出问题的Android版本。



作者:Wang_Guan
链接:https://www.jianshu.com/p/cd7480f0d17a


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消