前言
PopupWindow 和 Dialog 对于移动端来说都太平常了。 是最基础的控件, 所以对其的了解还是非常有必要的。
基本使用
1 | class MyPopupWindow(context: Context) : PopupWindow(context) { |
不做太多的代码, 上面的代码足矣我们分析其流程。 所以我们对其进行分析下。
源码分析
1 | public PopupWindow(Context context) { |
和 Dialog 中的一样, PopupWindow 也是持有 WMS。 那设置布局等也会跟 Dialog 一样吗? 我们接着看下 show 相关的代码。
1 | public void showAsDropDown(View anchor) { |
其中 attachToAnchor 是对相对的 view 做一些记录跟踪及保存。 中间会设置一些监听, 比如相对于的 view 发生了改变, 那么当前 popupWindow 也会跟着发生改变。 来我们来看下其实现。
1 | protected void attachToAnchor(View anchor, int xoff, int yoff, int gravity) { |
看着很清晰了, 先移出之前的 anchor, 然后在进行设置保存记录。
我们记着往下看。
1 | private void preparePopup(WindowManager.LayoutParams p) { |
看看我们看到了什么, 看到 DecorView, 还记得这个名词吧, 在 Activity 和 Dialog 是在 PhoneWindow 里创建的, 而 PopWindow 是在自身内部创建的。
1 | private PopupDecorView createDecorView(View contentView) { |
我们从 createDecorView 可以发现一个事情哈, 就是我们设置的布局不再是像 Activity 和 Dialog 一样, 添加到 id 为 content 中了, 而是直接 addView 添加了我们设置的布局。
我们可以看到 mDecorView 是 PopupDecorView。
1 | private class PopupDecorView extends FrameLayout { |
我们可以看到 PopupDecorView 是一个 FrameLayout, 其内部对事件进行了处理或者分发。
ok, 当这里, 我们还没有看到 View 添加到 WMS 进行管理显示呢, 我们接着往下看。
我们先看下 findDropDownPosition 方法。 这个方法在 invokePopup 之前。
1 | protected boolean findDropDownPosition(View anchor, WindowManager.LayoutParams outParams, |
可以看到该方法根据传入的偏移等数据计算和更新了当前 popupWindow 的一些 x、 y 等数据。
1 | private void invokePopup(WindowManager.LayoutParams p) { |
终于看到 WMS 添加 view 了。WMS 添加 view 的操作跟 Activity 和 Dialog 的一样, 这里不再多说了。 你可能会发现, 跟 Activity 和 Dialog 中间差了一个 window 层, 在具体点就是 popupWIndow 没有 PhoneWindow。
show 方法看过了, 我们看下 dismiss 方法。
1 | public void dismiss() { |
可以看到基本都是类似的, 调用 WMS 的 removeViewImmediate 方法。