Android WindowManagerService解析(4)

看篇文章之前,建议先看看前面几篇,这样理解会更深刻,下面我们来看看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会进行管理。

欢迎关注微信公众号:DroidMind
精品内容独家发布平台


呈现与博客不一样的技术干货

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值