欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

1.1.1UI绘制流程及原理——View是如何被添加到屏幕窗口上

程序员文章站 2024-03-24 10:03:40
...

本片文章讲解:UI绘制流程-源码讲解(基于API28的源码分析)

文章大纲:

part1:View是如何被添加到屏幕窗口上

part2:View的绘制流程

本片先讲part1:View是如何被添加到屏幕窗口上,part2:放在下一篇文章讲解。

 

part1:View是如何被添加到屏幕窗口上

首先,MainActivity中调用了setContentView(R.layout.activity_main);方法,我们跟进去,来到了Activity的源码当中:

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback{
    //省略....
    /**
     * Set the activity content from a layout resource.  The resource will be
     * inflated, adding all top-level views to the activity.
     *
     * @param layoutResID Resource ID to be inflated.
     *
     * @see #setContentView(android.view.View)
     * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
     */
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }
    //省略....
}

其中getWindow()方法返回了Window对象:

class Activity{
    /**
     * Retrieve the current {@link android.view.Window} for the activity.
     * This can be used to directly access parts of the Window API that
     * are not available through Activity/Screen.
     *
     * @return Window The current window, or null if the activity is not
     *         visual.
     */
    public Window getWindow() {
        return mWindow;
    }
}

继续查找Window这个类,发现类注释上面有这样一段话:

/**
 * Abstract base class for a top-level window look and behavior policy.  An
 * instance of this class should be used as the top-level view added to the
 * window manager. It provides standard UI policies such as a background, title
 * area, default key processing, etc.
 *
 * <p>The only existing implementation of this abstract class is
 * android.view.PhoneWindow, which you should instantiate when needing a
 * Window.
 */
public abstract class Window {

    //...
}

The only existing implementation of this abstract class is android.view.PhoneWindow,也就是说PhoneWindow是Window类的唯一继承实现。那么我们可以找到PhoneWindow类的setContentView方法了:

public class PhoneWindow extends Window implements MenuBuilder.Callback {

    //....

    @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();
        }
    }
   //....
}

在PhoneWindow类中有两个比较重要的方法installDecor()和mLayoutInflater.inflate(layoutResID, mContentParent)。接下来我们分别说一下这个两个方法的作用:

installDecor方法:

class PhoneWinow{

    private void installDecor() {
        if (mDecor == null) {
            mDecor = generateDecor();//注意这里 方法①
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        }
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);//注意这里 方法②
        }
    }

}

这里先提一句,就是在installDecor方法里面有一个mContentParent = generateLayout(mDecor);这里给mContentParent赋值之后,回到setContentView方法中也有一个mContentParent对象,调用的方法为 mLayoutInflater.inflate(layoutResID, mContentParent),这两个mContentParent是同一个对象。

 

然后我们跟进到generateDecor方法里面:

class PhoneWindow{
    protected DecorView generateDecor(int featureId) {
        // System process doesn't have application context and in that case we need to directly use
        // the context we have. Otherwise we want the application context, so we don't cling to the
        // activity.
        Context context;
        if (mUseDecorContext) {
            Context applicationContext = getContext().getApplicationContext();
            if (applicationContext == null) {
                context = getContext();
            } else {
                context = new DecorContext(applicationContext, getContext());
                if (mTheme != -1) {
                    context.setTheme(mTheme);
                }
            }
        } else {
            context = getContext();
        }
        return new DecorView(context, featureId, this, getAttributes());
    }
}

实际上就是生成了一个DecorView对象,我们看看DecorView到底是个什么?

public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
    //...

}

可以发现DecorView 实际上是一个FrameLayout,因此installDecor方法就是生成了一个DecorView容器对象,接下来分析:

 mContentParent = generateLayout(mDecor);方法

class PhoneWindow{
    protected ViewGroup generateLayout(DecorView decor) {
        // Apply data from current theme.

        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);
        }

        if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
            requestFeature(FEATURE_NO_TITLE);
        } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
            // Don't allow an action bar if there is no title.
            requestFeature(FEATURE_ACTION_BAR);
        }
        //...

        a.getValue(R.styleable.Window_windowMinWidthMajor, mMinWidthMajor);
        a.getValue(R.styleable.Window_windowMinWidthMinor, mMinWidthMinor);
        if (DEBUG) Log.d(TAG, "Min width minor: " + mMinWidthMinor.coerceToString()
                + ", major: " + mMinWidthMajor.coerceToString());
        if (a.hasValue(R.styleable.Window_windowFixedWidthMajor)) {
            if (mFixedWidthMajor == null) mFixedWidthMajor = new TypedValue();
            a.getValue(R.styleable.Window_windowFixedWidthMajor,
                    mFixedWidthMajor);
        }
        if (a.hasValue(R.styleable.Window_windowFixedWidthMinor)) {
            if (mFixedWidthMinor == null) mFixedWidthMinor = new TypedValue();
            a.getValue(R.styleable.Window_windowFixedWidthMinor,
                    mFixedWidthMinor);
        }
        //...


        // Inflate the window decor.

        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;
            setCloseOnSwipeEnabled(true);
        } 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!");
        } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
                && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
            // Special case for a window with only a progress bar (and title).
            // XXX Need to have a no-title version of embedded windows.
            layoutResource = R.layout.screen_progress;
            // System.out.println("Progress!");
        } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
            // Special case for a window with a custom title.
            // If the window is floating, we need a dialog layout
            if (mIsFloating) {
                TypedValue res = new TypedValue();
                getContext().getTheme().resolveAttribute(
                        R.attr.dialogCustomTitleDecorLayout, res, true);
                layoutResource = res.resourceId;
            } else {
                layoutResource = R.layout.screen_custom_title;
            }
            // XXX Remove this once action bar supports these features.
            removeFeature(FEATURE_ACTION_BAR);
        } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
            // If no other features and not embedded, only need a title.
            // If the window is floating, we need a dialog layout
            if (mIsFloating) {
                TypedValue res = new TypedValue();
                getContext().getTheme().resolveAttribute(
                        R.attr.dialogTitleDecorLayout, res, true);
                layoutResource = res.resourceId;
            } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
                layoutResource = a.getResourceId(
                        R.styleable.Window_windowActionBarFullscreenDecorLayout,
                        R.layout.screen_action_bar);
            } else {
                layoutResource = R.layout.screen_title;
            }
            // System.out.println("Title!");
        } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
            layoutResource = R.layout.screen_simple_overlay_action_mode;
        } else {
            // Embedded, so no decoration is needed.
            layoutResource = R.layout.screen_simple;
            // System.out.println("Simple!");
        }

        mDecor.startChanging();
        mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);//注意这里 ②

        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);//注意这里 ③
        if (contentParent == null) {
            throw new RuntimeException("Window couldn't find content container view");
        }

        if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
            ProgressBar progress = getCircularProgressBar(false);
            if (progress != null) {
                progress.setIndeterminate(true);
            }
        }

        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
            registerSwipeCallbacks(contentParent);
        }

        // Remaining setup -- of background and title -- that only applies
        // to top-level windows.
        if (getContainer() == null) {
            final Drawable background;
            if (mBackgroundResource != 0) {
                background = getContext().getDrawable(mBackgroundResource);
            } else {
                background = mBackgroundDrawable;
            }
            mDecor.setWindowBackground(background);

            final Drawable frame;
            if (mFrameResource != 0) {
                frame = getContext().getDrawable(mFrameResource);
            } else {
                frame = null;
            }
            mDecor.setWindowFrame(frame);

            mDecor.setElevation(mElevation);
            mDecor.setClipToOutline(mClipToOutline);

            if (mTitle != null) {
                setTitle(mTitle);
            }

            if (mTitleColor == 0) {
                mTitleColor = mTextColor;
            }
            setTitleColor(mTitleColor);
        }

        mDecor.finishChanging();

        return contentParent;//注意这里 ④
    }

}

这个方法狠多,我们只捡重点的说几个:

方法①处的含义为,layoutResource的字段赋值是依旧features等字段,这里我们以最后一个else为例,给layoutResource 赋值:

layoutResource = R.layout.screen_simple;

找到screen_simple布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">
    <ViewStub android:id="@+id/action_mode_bar_stub"
              android:inflatedId="@+id/action_mode_bar"
              android:layout="@layout/action_mode_bar"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:theme="?attr/actionBarTheme" />
    <FrameLayout
         android:id="@android:id/content"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:foregroundInsidePadding="false"
         android:foregroundGravity="fill_horizontal|top"
         android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>

注意一下FrameLayout的id是@android:id/content,后面会用到。

所以总结一下方法①的作用:根据设置的主题、features等字段的不同找到不同的对应布局给layoutResource赋值。

接下来进到方法②的分析,即:mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);,mDecor就是前面生成的DecorView对象,跟进到onResourcesLoaded方法里面去:

class DecorView{
    void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
        if (mBackdropFrameRenderer != null) {
            loadBackgroundDrawablesIfNeeded();
            mBackdropFrameRenderer.onResourcesLoaded(
                    this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
                    mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
                    getCurrentColor(mNavigationColorViewState));
        }

        mDecorCaptionView = createDecorCaptionView(inflater);
        final View root = inflater.inflate(layoutResource, null);//注意这里 ①
        if (mDecorCaptionView != null) {
            if (mDecorCaptionView.getParent() == null) {
                addView(mDecorCaptionView,
                        new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));//注意这里 ②
            }
            mDecorCaptionView.addView(root,
                    new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
        } else {

            // Put it below the color views.
            addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));//注意这里③
        }
        mContentRoot = (ViewGroup) root;
        initializeElevation();
    }
}

这个方法有三处需要注意的,方法①:final View root = inflater.inflate(layoutResource, null);

意思就是根据上面赋值的layoutResource然后inflate成一个View对象名称为root,方法②③addView方法,含义就是将生成的root这个View添加到DecorView里面,DecorView是一个FragmeLayout对象。

到此我们也知道了onResourcesLoaded的作用就是将找到的layoutResource布局生成View然后添加到DecorView身上。

 

接下来回去继续分析PhoneWindow类中的generatorLayout方法中第二处:ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

ID_ANDROID_CONTENT是Window类中的定义的一个静态常量:

class Window{
    /**
     * The ID that the main layout in the XML layout file should have.
     */
    public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
}

我们可以发现这个id就是之前我们在布局screen_simple里面FrameLayout的id!

所以通过findViewById方法之后找到了contentParent容器,然后返回到调用之处。回到调用之处:

class PhoneWinow{

    private void installDecor() {
        if (mDecor == null) {
            mDecor = generateDecor();//注意这里 方法①
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        }
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);//注意这里 方法②
        }
    }

}

继续回到installDecor调用之处:

public class PhoneWindow extends Window implements MenuBuilder.Callback {

    //....

    @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();
        }
    }
   //....
}

此时installDecor方法走完,mContentParent也赋值完毕,mContentParent就等于布局screen_simple里面FrameLayout!

接下来走方法②: mLayoutInflater.inflate(layoutResID, mContentParent);这个就比较好理解了,即将传进来的布局layoutResID加入到mContengParent里面,即screen_simple布局中的FrameLayout容器里面!

 

以上就是View是如何被添加到屏幕窗口全部分析,接下来我们总结一下:

首先,系统会创建一个顶层布局容器DecorView,它是一个ViewGroup,继承FrameLayout,是PhoneWindow持有的一个实例,它(PhoneWindow)是所有应用程序的顶层View,在系统内部初始化。

当DecorView初始化完成之后,系统会根据应用程序的主题特性去加载一个基础容器,比如dart actionbar、noactionbar等主题加载的基础容器也是不同的。但无论如何这个基础容器里面一定会有一个com.android.internal.R.id.content的容器,这个容器就是FragmeLayout。

而我们开发者通过setContentView(R.layout.activity_main)的XML布局文件就是通过解析之后添加到上面的FragmeLayout中。

接下来我们用不同类的形式再汇总说一下:

涉及到的类如下:

1.1.1UI绘制流程及原理——View是如何被添加到屏幕窗口上

MainActivity:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /**
         * 加载XML布局activity_main
         */
        setContentView(R.layout.activity_main);
    }
}

Activity:

public class Activity {

    /**
     * MainActivity的setContentView方法会调到这里来
     * @param layoutResID 布局id
     */
    public void setContentView(@LayoutRes int layoutResID) {
        //getWindow()返回PhoneWindow对象,实际会走到PhoneWindow.setContentView方法中
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

    /**
     * 返回Window对象,实际是PhoneWindow对象
     * @return Window对象
     */
    public Window getWindow() {
        return mWindow;
    }

}

Window:

/**
 * PhoneWindow是Window的唯一实现
 */
public abstract class Window {

    /**
     * 这个id是布局文件中FragmeLayout中的id
     */
    public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;

}

PhoneWindow:

public class PhoneWindow extends Window implements MenuBuilder.Callback {

    /**
     * MainActivity.setContentView-->Activity.setContentView-->PhoneWindow.setContentView
     *
     * @param layoutResID 传入的布局id,此处可以理解为R.layout.activity_main
     */
    @Override
    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            /**
             *  这个方法作用:
             *  1.生成DecorView对象(DecorView是继承FrameLayout)
             *  2.初始化mContentParent对象
             */
            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 {
            /**
             *这个方法作用:
             * 将传进来的布局加载到mContentParent容器中
             */
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }

    /**
     * 里面有两个重要的方法:
     * 1. generateDecor:如果mDecor为空,则生成DecorView
     * 2. generateLayout:
     */
    private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
            //生成DecorView,DecorView是继承FrameLayout
            mDecor = generateDecor(-1);
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        } else {
            mDecor.setWindow(this);
        }
        if (mContentParent == null) {
            //
            mContentParent = generateLayout(mDecor);
        }
    }

    /**
     * 生成DecorView 对象
     */
    protected DecorView generateDecor(int featureId) {
        Context context;
        if (mUseDecorContext) {
            Context applicationContext = getContext().getApplicationContext();
            if (applicationContext == null) {
                context = getContext();
            } else {
                context = new DecorContext(applicationContext, getContext());
                if (mTheme != -1) {
                    context.setTheme(mTheme);
                }
            }
        } else {
            context = getContext();
        }
        return new DecorView(context, featureId, this, getAttributes());
    }

    /**
     *找相应的加载布局,加载到DecorView中,然后返回布局中FragmeLayout对象
     * @param decor
     * @return 布局中id为ID_ANDROID_CONTENT的容器
     */
    protected ViewGroup generateLayout(DecorView decor) {
        TypedArray a = getWindowStyle();
        //省略...
        //解析属性值
        if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
            requestFeature(FEATURE_NO_TITLE);
        } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
            requestFeature(FEATURE_ACTION_BAR);
        }

        if (a.getBoolean(R.styleable.Window_windowActionBarOverlay, false)) {
            requestFeature(FEATURE_ACTION_BAR_OVERLAY);
        }

        if (a.getBoolean(R.styleable.Window_windowActionModeOverlay, false)) {
            requestFeature(FEATURE_ACTION_MODE_OVERLAY);
        }

        // 根据features和属性的不同,来给layoutResource赋值,实际就是找相应的加载布局
        int layoutResource;
        int features = getLocalFeatures();
        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
            layoutResource = R.layout.screen_swipe_dismiss;
            setCloseOnSwipeEnabled(true);
        } else if {
            //省略...
        }else{
            layoutResource = R.layout.screen_simple;
        }

        mDecor.startChanging();
        //将找到的布局layoutResource加入到DecorView中去
        mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
        //找到layoutResource布局中id为ID_ANDROID_CONTENT的控件,然后返回
        ViewGroup contentParent = (ViewGroup) findViewById(ID_ANDROID_CONTENT);
        //省略...
        return contentParent;
    }
}

DecorView:

public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {

    /**
     * 根据传入的layoutResource生成View,然后将它加入到DecorView里面
     *
     * @param inflater 布局生成器
     * @param layoutResource 布局id
     */
    void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
        if (mBackdropFrameRenderer != null) {
            loadBackgroundDrawablesIfNeeded();
            mBackdropFrameRenderer.onResourcesLoaded(
                    this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
                    mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
                    getCurrentColor(mNavigationColorViewState));
        }

        mDecorCaptionView = createDecorCaptionView(inflater);
        //根据layoutResource生成view对象
        final View root = inflater.inflate(layoutResource, null);
        if (mDecorCaptionView != null) {
            if (mDecorCaptionView.getParent() == null) {
                addView(mDecorCaptionView, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
            }
            //将生成的布局View加入到DecorView中
            mDecorCaptionView.addView(root, new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
        } else {
            //将生成的布局View加入到DecorView中
            addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        }
        mContentRoot = (ViewGroup) root;
        initializeElevation();
    }
}

最后画一个图来说一下:

1.1.1UI绘制流程及原理——View是如何被添加到屏幕窗口上

相信看到这里,大家都应该明白View视图是如何被添加到屏幕上了。

END.