View绘制之setContentView()源码分析

Activity的setContentView()

public void setContentView(View view, ViewGroup.LayoutParams params) {
    getWindow().setContentView(view, params);
    initWindowDecorActionBar();
}

调用了Window的setContentView(),然后创建一个ActionBar。

Window的setContentView()

abstract class Window:概括了Android窗口的基本属性和基本功能。
顶级窗口外观和行为策略的抽象基类。这个类的实例用做顶级View添加进window manager。提供标准UI规范如背景、标题区域、默认键盘进程等。
而window在整个布局的id就是R.id.content

Window的实现类PhoneWindow的setContentView()

@Override
public void setContentView(int layoutResID) {
    // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
    // decor, when theme attributes and the like are crystalized. Do not check the feature
    // before this happens.
    if (mContentParent == null) {
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }

    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                getContext());
        transitionTo(newScene);
    } else {
        mLayoutInflater.inflate(layoutResID, mContentParent);
    }
    mContentParent.requestApplyInsets();
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
}

首先判断mContentParent是否为null,是则调用installDecor(),否则移除其内部所有的子Views,然后通过LayoutInflater.inflate将我们传入的layout放置到mContentParent中。
最后设置Callback(即window所属Activity),CallBack接口拦截键盘、面板、菜单等操作。

installDecor()

private void installDecor() {
    // 首先判断mDecor是否为空,成立就创建一个新的Decor并初始化。
    if (mDecor == null) {
        mDecor = generateDecor();
        // 当子View都不需要焦点时,decor才获取焦点。
        mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        mDecor.setIsRootNamespace(true);
        if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
            mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
        }
    }
    //
    if (mContentParent == null) {
        // 生成mContentParent
        mContentParent = generateLayout(mDecor);
        // 根据定义的样式设置title,图标,background等。

        // 如果调用没自定义TransitionManager就创建一个新的。
    }
}

Decor继承自FrameLayout。

generateDecor()

protected ViewGroup generateLayout(DecorView decor) {
    // Apply data from current theme.
    // 首先通过WindowStyle中设置的各种属性,对Window进行requestFeature或者setFlags
    TypedArray a = getWindowStyle();

    mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
    int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
            & (~getForcedWindowFlags());
    if (mIsFloating) {
        setLayout(WRAP_CONTENT, WRAP_CONTENT);
        setFlags(0, flagsToUpdate);
    } else {
        setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
    }


    //...根据当前sdk的版本确定是否需要menukey
    final Context context = getContext();
    ......
    if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) {
        setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE);
    } else {
        setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_FALSE);
    }

     //通过a中设置的属性,设置  params.softInputMode 软键盘的模式; 
    //如果当前是浮动Activity,在params中设置FLAG_DIM_BEHIND并记录dimAmount的值。 
    //以及在params.windowAnimations记录WindowAnimationStyle
    ......

    // 所有的都做完了只是window没嵌入。否则,值从容器继承
    if (getContainer() == null) {
        if (mBackgroundDrawable == null) {
            if (mBackgroundResource == 0) {
                mBackgroundResource = a.getResourceId(
                        R.styleable.Window_windowBackground, 0);
            }
            if (mFrameResource == 0) {
                mFrameResource = a.getResourceId(R.styleable.Window_windowFrame, 0);
            }
            mBackgroundFallbackResource = a.getResourceId(
                    R.styleable.Window_windowBackgroundFallback, 0);
            if (false) {
                System.out.println("Background: "
                        + Integer.toHexString(mBackgroundResource) + " Frame: "
                        + Integer.toHexString(mFrameResource));
            }
        }
        mElevation = a.getDimension(R.styleable.Window_windowElevation, 0);
        mClipToOutline = a.getBoolean(R.styleable.Window_windowClipToOutline, false);
        mTextColor = a.getColor(R.styleable.Window_textColor, Color.TRANSPARENT);
    }

    // 填充window decor
    // 通过对features和mIsFloating的判断,为layoutResource进行赋值,所以requestFeature要在setContentView之前进行

    int layoutResource;
    int features = getLocalFeatures();
    // System.out.println("Features: 0x" + Integer.toHexString(features));
    if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
        layoutResource = R.layout.screen_swipe_dismiss;
    } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
        if (mIsFloating) {
            TypedValue res = new TypedValue();
            getContext().getTheme().resolveAttribute(
                    R.attr.dialogTitleIconsDecorLayout, res, true);
            layoutResource = res.resourceId;
        } else {
            layoutResource = R.layout.screen_title_icons;
        }
        // XXX Remove this once action bar supports these features.
        removeFeature(FEATURE_ACTION_BAR);
        // System.out.println("Title Icons!");
    }
    ......
    mDecor.startChanging();
    // 把layout转化成view添加到decor
    View in = mLayoutInflater.inflate(layoutResource, null);
    decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    mContentRoot = (ViewGroup) in;

    // 通过mDecor.findViewById传入R.id.content
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
    if (contentParent == null) {
        throw new RuntimeException("Window couldn't find content container view");
    }
    ......

    // 剩余设置--背景和标题--只适用于顶级窗口
    if (getContainer() == null) {
        ......
    }

    mDecor.finishChanging();

    return contentParent;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值