全面了解Window

本文详细探讨了Android中的Window概念,包括它的前置知识、问题、基本操作和流程分析。讲解了Window与Activity、Dialog的区别,重点解析了Window的创建、布局、绘制流程,并通过实例展示了如何查看和管理Window。此外,还提到了WindowManager用于管理Window,以及如何拦截键盘消息。
摘要由CSDN通过智能技术生成

前置知识

  1. Window是什么?Window是一个组件,View是由Window呈现出来的。Window实际上就是管理着View,对Window的操作最终都会转化成对View的操作。
  2. 经常使用的WindowActivityDialogPopupWindowToast等。系统中常见的WindowStatusBarNavigationBarInputMethod(软键盘)等。StatusBarNavigationBar等是在单独的进程中使用的。

问题

1.WindowManager.LayoutParam(继承ViewGroup.LayoutParams)类很重要,flagstype 等等。

type,相当于Window 的类型,主要分为3大类。

  • 1-99对应应用Window(token 必须设置为Activity 的token,即Context需要设置为Activity)。Activity 中的Window 对应的type 是TYPE_BASE_APPLICATIONDialog默认的是TYPE_APPLICATIONWindowManager.LayoutParams默认构造函对应的type也是TYPE_APPLICATION
  • 1000-1999对应子Window。PopupWindow 默认是TYPE_APPLICATION_PANEL
  • 2000-2999 对应的是系统Window。Toast对应TYPE_TOAST,StatusBar对应TYPE_STATUS_BARNavigationBar对应TYPE_NAVIGATION_BAR,键盘对应着”TYPE_INPUT_METHOD”。

flags,各种不一样属性,控制Window 的一些特殊显示。

2.DialogPopupWindow的异同。

  • DialogPopupWindoow 都会在一个新的Window中展示。
  • Dialog不能使用ApplicationContext,上面就可以知道Dailog是应用Window,只能使用Activity
  • PopupWindow不能在Activity.onCreate中创建。PopupWindow默认是一个子Window,需要在Activity创建以后使用。
  • PopupWindow一定需要设置widthheight,默认是0。
  • Dialog是创建了一个PhoneWindow然后获取的DecorView,所有默认有Title,而PopupWindow没有。
  • PopupWindow默认不会响应Back键,可以设置popupWindow.setFocusable(true);
  • 通过Activity来管理Dialog的时候,Activity.mManagedDialogs,当Activity后台销毁的时候再次进入可以恢复(参考Dialog.onSaveInstanceStateDialog.onRestoreInstanceState)。而PopupWindow没有恢复机制。

至于网上很多说PopupWindow是阻塞式的而Dialog是非阻塞式的,是非常误解人的。关于坑爹的PopupWindow的“阻塞”争议问题:Android没有真正的“阻塞式”对话框

3.Toast展示以后可以将Toast点击的事件传递到下面的View,Dialog以及Popupindow都不行,跟WindowManager.LayoutParams.flags有关。

4.Activity设置windowSoftInputMode属性的时候,会对ActivityWindow有一些影响。

5.一个App 中有多少个Window?应该是某个状态下Window的个数,Activity+Dialog+PopupWindow+Toast+WindowManage.addView

基本操作

WindowManager继承ViewManager,基本的操作如下。操作的实际上是ViewWindowManagerImpl保存着一族对应的mViewsmRootsmParams。对于每一个展示的Window实际上对应着mViews[k]mRoots[k]mParams[k]。具体可以看后面的流程分析。

// ViewManager.java
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);

流程分析

Window.setStatusBarColor流程(api 21以上)。

StatusBarNavigationBar都是一个View展示在最上面和最下面??

1.Window.setStatusBarColor`。

// PhoneWindow.java
@Override
public void setStatusBarColor(int color) {
    mStatusBarColor = color;
    mForcedStatusBarColor = true;
    if (mDecor != null) {
        // 直接调用到了DecorView.updateColorViews()
        mDecor.updateColorViews(null, false /* animate */);
    }
}

2.DecorView.updateColorViews。从代码中看就是修改了mNavigationColorViewStatemStatusColorViewState里面包含的ViewbackgroundColor

// DecorView.java
private WindowInsets updateColorViews(WindowInsets insets, boolean animate) {
    // insets null  animate false
    WindowManager.LayoutParams attrs = getAttributes();
    // 获取系统状态栏的显示属性
    int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();
    if (!mIsFloating && ActivityManager.isHighEndGfx()) {
        boolean disallowAnimate = !isLaidOut();
        disallowAnimate |= ((mLastWindowFlags ^ attrs.flags)
                & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
        mLastWindowFlags = attrs.flags;
        if (insets != null) {
            // 省略相关代码
        }

        // 这里相当于是横竖屏判断
        boolean navBarToRightEdge = mLastBottomInset == 0 && mLastRightInset > 0;
        int navBarSize = navBarToRightEdge ? mLastRightInset : mLastBottomInset;
        // 更新Navigation
        updateColorViewInt(mNavigationColorViewState, sysUiVisibility, mNavigationBarColor,
                navBarSize, navBarToRightEdge, 0 /* rightInset */,
                animate && !disallowAnimate);

        boolean statusBarNeedsRightInset = navBarToRightEdge
                && mNavigationColorViewState.present;
        int statusBarRightInset = statusBarNeedsRightInset ? mLastRightInset : 0;
        // 更新Status
        updateColorViewInt(mStatusColorViewState, sysUiVisibility, mStatusBarColor,
                mLastTopInset, false /* matchVertical */, statusBarRightInset,
                animate && !disallowAnimate);
    }

    // 省略代码
    return insets;
}

3.DecorView.updateColorViewInt

// DecorView.java
private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color,
    int size, boolean verticalBar, int rightMargin, boolean animate, boolean force) {
    // animate false
    state.present = (sysUiVis & state.systemUiHideFlag) == 0
            && (mWindow.getAttributes().flags & state.hideWindowFlag) == 0
            && ((mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
                || force);
    boolean show = state.present
            && (color & Color.BLACK) != 0
            && ((mWindow.getAttributes().flags & state.translucentFlag) == 0  || force);
    boolean showView = show && !isResizing() && size > 0;

    boolean visibilityChanged = false;
    View view = state.view;

    int resolvedHeight = verticalBar ? LayoutParams.MATCH_PARENT : size;
    int resolvedWidth = verticalBar ? size : LayoutParams.MATCH_PARENT;
    // 横屏和竖屏展示的为位置不一样,分别对应着设置的horizontalGravity和verticalGravity
    int resolvedGravity = verticalBar ? state.horizontalGravity : state.verticalGravity;

    if (view == null) {
        if (showView) {
            // 为空会创建。相当于创建了Navigation 和Status View
            // 即改变StatusBar/NavigationBar 实际上是改变了一个View 的颜色
            state.view = view = new View(mContext);
            view.setBackgroundColor(color);
            view.setTransitionName(state.transitionName);
            view.setId(state.id);
            visibilityChanged = true;
            view.setVisibility(INVISIBLE);
            state.targetVisibility = VISIBLE;

            LayoutParams lp = new LayoutPara
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值