Android WindowManagerService解析(4)

来源:互联网 发布:淘宝模特余露工作室 编辑:程序博客网 时间:2024/06/07 14:36

看篇文章之前,建议先看看前面几篇,这样理解会更深刻,下面我们来看看PopupWindow的显示过程

一、PopupWindow的创建

public PopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {        mContext = context;        // 得到一个WindowManager对象        mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);}

二、setContentView

public void setContentView(View contentView) {    if (isShowing()) {        return;    }    mContentView = contentView;    if (mContext == null && mContentView != null) {        mContext = mContentView.getContext();    }    if (mWindowManager == null && mContentView != null) {        mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);    }}

就是将contentView赋值给成员变量mContentView,并且确保mWindowManager对象不为null。

三、显示过程

我们这里以showAtLocation函数为例,进行查看

public void showAtLocation(IBinder token, int gravity, int x, int y) {    if (isShowing() || mContentView == null) {        return;    }    unregisterForScrollChanged();    mIsShowing = true;    mIsDropdown = false;    // 1、获取布局属性    WindowManager.LayoutParams p = createPopupLayout(token);    p.windowAnimations = computeAnimationResource();    // 2、做一些准备工作    preparePopup(p);    if (gravity == Gravity.NO_GRAVITY) {        gravity = Gravity.TOP | Gravity.START;    }    p.gravity = gravity;    p.x = x;    p.y = y;    if (mHeightMode < 0) p.height = mLastHeight = mHeightMode;    if (mWidthMode < 0) p.width = mLastWidth = mWidthMode;    // 3、进行显示    invokePopup(p);}

从前面的分析我们知道,WindowManager添加一个view需要两个参数,一个是需要添加的view对象,一个是布局属性,在前面的setContent函数已经给出了需要添加的view了,对于布局属性就在createPopupLayout函数中生成。

private WindowManager.LayoutParams createPopupLayout(IBinder token) {    WindowManager.LayoutParams p = new WindowManager.LayoutParams();    p.gravity = Gravity.START | Gravity.TOP;    p.width = mLastWidth = mWidth;    p.height = mLastHeight = mHeight;    if (mBackground != null) {        p.format = mBackground.getOpacity();    } else {        p.format = PixelFormat.TRANSLUCENT;    }    p.flags = computeFlags(p.flags);    p.type = mWindowLayoutType;    p.token = token;    p.softInputMode = mSoftInputMode;    p.setTitle("PopupWindow:" + Integer.toHexString(hashCode()));    return p;}

下面看看显示过程,其实猜都可以猜到,我们的view以及该view对应的布局属性已经准备好了,下面就是直接调用windowManager的addView方法,下面我们看看invokePopup函数。

private void invokePopup(WindowManager.LayoutParams p) {    if (mContext != null) {        p.packageName = mContext.getPackageName();    }    mPopupView.setFitsSystemWindows(mLayoutInsetDecor);    setLayoutDirectionFromAnchor();    mWindowManager.addView(mPopupView, p);}

这里看到使用的是mPopupView,但是在前面setContentView中设置的是mContentView,其实mPopupView对应的就是mContentView,它的赋值操作在preparePopup函数中。

private void preparePopup(WindowManager.LayoutParams p) {    if (mBackground != null) {        final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();        int height = ViewGroup.LayoutParams.MATCH_PARENT;        if (layoutParams != null &&                layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT) {            height = ViewGroup.LayoutParams.WRAP_CONTENT;        }        // when a background is available, we embed the content view        // within another view that owns the background drawable        PopupViewContainer popupViewContainer = new PopupViewContainer(mContext);        PopupViewContainer.LayoutParams listParams = new PopupViewContainer.LayoutParams(                ViewGroup.LayoutParams.MATCH_PARENT, height        );        popupViewContainer.setBackgroundDrawable(mBackground);        popupViewContainer.addView(mContentView, listParams);        mPopupView = popupViewContainer;    } else {        mPopupView = mContentView;    }    mPopupViewInitialLayoutDirectionInherited =            (mPopupView.getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT);    mPopupWidth = p.width;    mPopupHeight = p.height;}

这里对mContentView做了一些处理然后赋值给了mPopupView。

从这里我们可以看到,对应界面的显示,其实思路都是一样的,都是使用的WindowManager,也就是说WindowManagerService对我们所有的UI会进行管理。

阅读全文
0 0