近期有网友根据 Android 必知必会 - DialogFragment 使用总结 做一些业务,但是目标却是用 DialogFragment 实现类似 PopupWindow 效果:
- 只拦截自身所占空间部分的事件,其余空间的点击事件不处理
- 可以根据某个 View 定位自身位置
虽然在功能上 PopupWindow 更符合需要,但是使用 DialogFragment 代码更简洁、更方便封装功能模块。
基础知识点
WindowManager.LayoutParams.flags
WindowManager.LayoutParams.flags
修改 Window 的表现行为
1 | /** |
以上可以看到它有很多可选项,加上可以多个相互组合,能满足很多需求,这里重点关注三个属性值:
FLAG_NOT_TOUCH_MODAL
Window flag: even when this window is focusable (its
FLAG_NOT_FOCUSABLE
is not set), allow any pointer events outside of the window to be sent to the windows behind it.(API level 1)
FLAG_TRANSLUCENT_NAVIGATION
Window flag: request a translucent navigation bar with minimal system-provided background protection.
(API level 19)
FLAG_TRANSLUCENT_STATUS
Window flag: request a translucent status bar with minimal system-provided background protection.
(API level 19)
更详细的介绍请点击 文档
其中 FLAG_NOT_TOUCH_MODAL
可达到『只拦截自身所占空间部分的事件,其余空间的点击事件不处理』的需求,而 FLAG_TRANSLUCENT_NAVIGATION
和 FLAG_TRANSLUCENT_STATUS
主要是用来调整使用沉浸式状态栏时显示自身位置不正确的问题。
获取 View 位置的时机
如果需要让 DialogFragment 在 onCreate()
等生命周期函数内直接调用显示到某个 View 的位置处,可能无法正确获取到该 View 的坐标,具体参考 Android必知必会-获取View坐标和长宽的时机 一文。
但是,如果在界面显示给用户后,DialogFragment 的显示交给用户触发的话,就不需要在意这个问题了。
代码实现
TopFragment.java
1 | public class TopFragment extends DialogFragment { |
MainActivity.java
1 |
|
注意:如果当前 Activity 使用了沉浸式状态栏,需要使用 TopFragment.getInstant(int y, boolean isTranslucentDecor)
方法,并且 isTranslucentDecor
传值为 true
。
效果图
未使用沉浸式状态栏、 isTranslucentDecor 传值为 false ,位置正确 |
使用沉浸式状态栏、 isTranslucentDecor 传值为 false ,位置定位差个状态栏高度 |
使用沉浸式状态栏、 isTranslucentDecor 传值为 true ,位置正确 |
---|---|---|
总结
总的来说,这里基本完成了要求的效果,但是定位只能指定其顶部开始的位置,不方便底部定位到某个 View 的上面,因为高度自适应的话,在页面渲染完成前是不能知道它的高度的。当然,你可以使用固定高度布局的方式来实现随意定位。
有什么建议或者问题可以随时联系我,共同探讨学习: