PopupWindow之了解

来源:互联网 发布:unity3d灯光闪烁效果 编辑:程序博客网 时间:2024/05/29 18:48

在分析PopupWindow之前,我们将首先说一下什么是PopupWindow?理解一个类最好的方式就是看一下这个类的定义,这里我们摘要了一下Android系统中PopupWindow的类的说明:

A popup window that can be used to display an arbitrary view. The popup window is a floating container that appears on top of the current 
activity.

一个PopupWindow能够被用于展示任意的View,PopupWindow是一个悬浮的容易展示在当前Activity的上面。 
简单来说PopupWindow就是一个悬浮在Activity之上的窗口,可以用展示任意布局文件。

PopupWindow 设置可点击可有两种方法~

1、在构造函数中 super(activity)

2、给PopupWindow 设置一个背景:如:

ColorDrawable dw = new ColorDrawable(0x00000000);
setBackgroundDrawable(dw);

在说明PopupWindow的加载绘制机制之前,我们还是先写一个简单的例子用于说明一下PopupWindow的简单用法。

<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">public static View showPopupWindowMenu(Activity mContext, View anchorView, int layoutId) {        LayoutInflater inflater = (LayoutInflater) mContext<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getSystemService</span>(Context<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.LAYOUT</span>_INFLATER_SERVICE)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>        View view = inflater<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.inflate</span>(layoutId, null)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>        popupWindow = new PopupWindow(view, DisplayUtil<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.dip</span>2px(mContext, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">148</span>), WindowManager<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.LayoutParams</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.WRAP</span>_CONTENT)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>        popupWindow<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setBackgroundDrawable</span>(mContext<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getResources</span>()<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getDrawable</span>(R<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.drawable</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.menu</span>_bg))<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>        popupWindow<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setFocusable</span>(true)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>        popupWindow<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setOutsideTouchable</span>(true)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>        int[] location = new int[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>]<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>        anchorView<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getLocationOnScreen</span>(location)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>        popupWindow<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setAnimationStyle</span>(R<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.style</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.popwin</span>_anim_style)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>        popupWindow<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.showAtLocation</span>(anchorView, Gravity<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.NO</span>_GRAVITY,                location[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] - popupWindow<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getWidth</span>() + anchorView<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getWidth</span>() - DisplayUtil<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.dip</span>2px(mContext, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">12</span>),                location[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>] + anchorView<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getHeight</span>() - DisplayUtil<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.dip</span>2px(mContext, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>))<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>        popupWindow<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setOnDismissListener</span>(new PopupWindow<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.OnDismissListener</span>() {            @Override            public void onDismiss() {                popupWindow = null<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>            }        })<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>        return view<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul>

可以看到我们首先通过LayoutInflater对象将布局文件解析到内存中View对象,然后创建了一个PopupWindow对象,可以看到传递了三个参数,一个是View对象,一个是PopupWindow的宽度和高度。

这里就是PopupWindow的初始化流程的开始了,好吧,我们来看一下PopupWindow的构造方法的实现:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">PopupWindow</span>(View contentView, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> width, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> height) {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>(contentView, width, height, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>);    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

可以看到这里调用了PopupWindow的重载构造方法,好吧,继续看一下这个重载构造方法的实现逻辑:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">PopupWindow</span>(View contentView, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> width, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> height, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> focusable) {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (contentView != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {            mContext = contentView.getContext();            mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);        }        setContentView(contentView);        setWidth(width);        setHeight(height);        setFocusable(focusable);    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>

这里首先根据传入的View是否为空做了一下判断,若不为空,则初始化成员变量,Context和mWindowManager,可以发现这里的mContext对象就是传入的View组件中保留的Context对象,这里的mWindowManager是应用进程创建的时候注册的服务本地接口。然后调用了setContentView方法,这里就是为PopupWindow的contentView赋值。然后后面调用的setWidth、setHeight、setFocusable方法都是为PopupWindow的成员变量,width,height,focusable等赋值,这样PopupWindow的构造方法就执行完成了。

我们继续回到我们的例子代码中,在后续的代码中我们调用了:popupWindow.setBackgroundDrawable、popupWindow.setFocusable、PopupWindow.setOutsideTouchable、 
PopupWindow.setAnimationStyle等方法,初始化了PopupWindow中的相关成员变量,最后我们调用了popupWindow.showAtLocation方法用于展示PopupWindow,这里我们具体看一下showAtLocation的实现逻辑:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">showAtLocation</span>(View parent, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> gravity, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> x, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> y) {        showAtLocation(parent.getWindowToken(), gravity, x, y);    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

可以发现,这里调用了showAtLocation的重载函数,这样我们继续看一下这个重载函数的实现方式:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">showAtLocation</span>(IBinder token, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> gravity, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> x, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> y) {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (isShowing() || mContentView == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>;        }        TransitionManager.endTransitions(mDecorView);        unregisterForScrollChanged();        mIsShowing = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>;        mIsDropdown = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>;        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> WindowManager.LayoutParams p = createPopupLayoutParams(token);        preparePopup(p);        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Only override the default if some gravity was specified.</span>        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (gravity != Gravity.NO_GRAVITY) {            p.gravity = gravity;        }        p.x = x;        p.y = y;        invokePopup(p);    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li></ul>

可以看到通过调用createPopupLayoutParams方法创造了WindowManager.LayoutParams对象,然后又调用了preparePopup方法,可以看一下preparePopup方法的具体实现:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">preparePopup</span>(WindowManager.LayoutParams p) {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mContentView == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> || mContext == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> || mWindowManager == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> IllegalStateException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"You must specify a valid content view by "</span>                    + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"calling setContentView() before attempting to show the popup."</span>);        }        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// The old decor view may be transitioning out. Make sure it finishes</span>        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// and cleans up before we try to create another one.</span>        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mDecorView != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {            mDecorView.cancelTransitions();        }        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// When a background is available, we embed the content view within</span>        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// another view that owns the background drawable.</span>        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mBackground != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {            mBackgroundView = createBackgroundView(mContentView);            mBackgroundView.setBackground(mBackground);        } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {            mBackgroundView = mContentView;        }        mDecorView = createDecorView(mBackgroundView);        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// The background owner should be elevated so that it casts a shadow.</span>        mBackgroundView.setElevation(mElevation);        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// We may wrap that in another view, so we'll need to manually specify</span>        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// the surface insets.</span>        final <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> surfaceInset = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>) Math.ceil(mBackgroundView.getZ() * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>);        p.surfaceInsets.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">set</span>(surfaceInset, surfaceInset, surfaceInset, surfaceInset);        p.hasManualSurfaceInsets = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>;        mPopupViewInitialLayoutDirectionInherited =                (mContentView.getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT);        mPopupWidth = p.width;        mPopupHeight = p.height;    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li></ul>

preparePopup方法的参数是WindowManager.LayoutParams,然后设置了PopupWindow中的几个比较重要的成员变量,首先看一下mBackgroundView的初始化过程:

<code class="hljs matlab has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mBackground != null) <span class="hljs-cell" style="box-sizing: border-box;">{            mBackgroundView = createBackgroundView(mContentView);            mBackgroundView.setBackground(mBackground);        }</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> <span class="hljs-cell" style="box-sizing: border-box;">{            mBackgroundView = mContentView;        }</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>

可以发现如果我们设置了mBackground变量也就是我们在初始化的时候执行了popupWindow的setBackgound方法,那么我们这里执行的就是if分之,这里看一下createBackgourndView的具体执行逻辑:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> PopupBackgroundView <span class="hljs-title" style="box-sizing: border-box;">createBackgroundView</span>(View contentView) {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> height;        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (layoutParams != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> && layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT) {            height = ViewGroup.LayoutParams.WRAP_CONTENT;        } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {            height = ViewGroup.LayoutParams.MATCH_PARENT;        }        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> PopupBackgroundView backgroundView = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> PopupBackgroundView(mContext);        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> PopupBackgroundView.LayoutParams listParams = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> PopupBackgroundView.LayoutParams(                ViewGroup.LayoutParams.MATCH_PARENT, height);        backgroundView.addView(contentView, listParams);        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> backgroundView;    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>

可以看到,createBackgroundView的执行逻辑就是在参数contentView的外面一层包裹一层PopupBackgroundView,而这里的PopupBackgroundView值我们自定义的FrameLayout的子类,重写了其onCreateDrawableState方法。

继续回到我们的preparePopup方法,这里我们又调用了createDecorView方法初始化mDectorView变量,我们可以看一下createDecorView的具体实现:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> PopupDecorView <span class="hljs-title" style="box-sizing: border-box;">createDecorView</span>(View contentView) {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> height;        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (layoutParams != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> && layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT) {            height = ViewGroup.LayoutParams.WRAP_CONTENT;        } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {            height = ViewGroup.LayoutParams.MATCH_PARENT;        }        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> PopupDecorView decorView = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> PopupDecorView(mContext);        decorView.addView(contentView, ViewGroup.LayoutParams.MATCH_PARENT, height);        decorView.setClipChildren(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>);        decorView.setClipToPadding(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>);        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> decorView;    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>

可以发现这里也是给参数contentView外面包裹了一层PopupDecorView,这里的PopupDecorView也是我们自定义的FrameLayout的子类,PopupDecorView的源码比较多,这里就不都贴出来了,这里具体看一下其onTouchEvent方法的实现:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">@Override        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> boolean <span class="hljs-title" style="box-sizing: border-box;">onTouchEvent</span>(MotionEvent <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>) {            final <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> x = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>.getX();            final <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> y = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>.getY();            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ((<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>.getAction() == MotionEvent.ACTION_DOWN)                    && ((x < <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) || (x >= getWidth()) || (y < <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) || (y >= getHeight()))) {                dismiss();                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>;            } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>.getAction() == MotionEvent.ACTION_OUTSIDE) {                dismiss();                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>;            } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> super.onTouchEvent(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>);            }        }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>

可以发现其重写了onTouchEvent时间,这样我们在点击popupWindow外面的时候就会执行pupopWindow的dismiss方法,取消PopupWindow。

好吧,继续回到我们的showAsDropDown方法,在执行完成preparePopup方法之后又调用了invokePopup方法,这里的方法应该就是具体执行PopupWindow的加载与显示逻辑了。这里我们具体看一下其实现逻辑:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">invokePopup</span>(WindowManager.LayoutParams p) {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mContext != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {            p.packageName = mContext.getPackageName();        }        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> PopupDecorView decorView = mDecorView;        decorView.setFitsSystemWindows(mLayoutInsetDecor);        setLayoutDirectionFromAnchor();        mWindowManager.addView(decorView, p);        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mEnterTransition != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {            decorView.requestEnterTransition(mEnterTransition);        }    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>

我们看到这里我们调用了mWindowManager.addView方法,看过我们前面几篇关于Dialog和Activity的加载与现实流程的同学应该知道这里的addView其实是我们布局绘制的流程,这里的mWindowManager是我们在调用PopupWIndow的构造函数的时候初始化的,其调用的是:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mWindowManager == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> && mContentView != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {            mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);        }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

而这里的mContext.getSystemService是一个接口其具体的实现是在ContextImpl中实现的,所以这里我们看一下ContextImpl的getSystemService的实现:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Object <span class="hljs-title" style="box-sizing: border-box;">getSystemService</span>(String name) {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> SystemServiceRegistry.getSystemService(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>, name);    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

好吧,在ContextImpl中的getSystemService方法又调用了SystemServiceRegister中的静态方法getSystemService,这样我们再看看一下在SystemServiceRegister是如何实现的。

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Object <span class="hljs-title" style="box-sizing: border-box;">getSystemService</span>(ContextImpl ctx, String name) {        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">get</span>(name);        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> fetcher != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> ? fetcher.getService(ctx) : <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>;    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

这里发现服务对象的获取就是通过一个SYSTEM_SERVICE_FETCHERS的map数据结构获取的,那么这个map对象的数据是何时填充的呢?通过查看源码我们发下在SystemServiceRegister中有一段静态代码主要用于注册本地服务接口,其中关于windowManagerService本地服务的代码如下:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">registerService(Context.WINDOW_SERVICE, WindowManager.class,                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> CachedServiceFetcher<WindowManager>() {            <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> WindowManager <span class="hljs-title" style="box-sizing: border-box;">createService</span>(ContextImpl ctx) {                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> WindowManagerImpl(ctx.getDisplay());            }});</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>

好吧,原来我们通过mContext.getSystemService获取的WindowManager其实际上是一个WindowManagerImpl对象,而我们调用的addView就是WindowManagerImpl的addView方法。

这样就回到了我们前几篇讲解的内容上了,通过调用WindowManagerImpl实现了布局文件的绘制流程。。。。

好了,经过上面的一系列的操作我们分析完了PopupWindow的加载绘制流程,其和Dialog,Activity的加载绘制流程类似,都是通过Window对象控制布局文件的加载与绘制流程。

总结:

  • PopupWindow的界面加载绘制流程也是通过Window对象实现的;

  • PopupWindow内部保存的mWindowManager对象通过ContextImpl中获取,并且取得的是WindowManagerImpl对象;

  • PopupWindow通过为传入的View添加一层包裹的布局,并重写该布局的点击事件,实现点击PopupWindow之外的区域PopupWindow消失的效果;

0 0