美文网首页
UI绘制流程及原理(一)

UI绘制流程及原理(一)

作者: 哆啦A猛 | 来源:发表于2019-08-29 16:14 被阅读0次

对于setContentView(R.layout.activity_main);相信大家都不陌生,我们初始化控件都要在它之后,下面简单说一下activity中的UI绘制流程

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

点击setContentView可以进入到Activity

   /**
    * 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(),我们点击查看

    /**
     * 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是一个抽象类,他只有一个实现类就是PhoneWindow,我们全局搜索PhoneWindow并找到他的setContentView方法,可以看到一个installDecor方法,点击进入

    @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();
        }
        mContentParentExplicitlySet = true;
    }

而installDecor()中,主要有两个比较重要的方法

1.generateDecor(-1);它主要是创建一个DecorView,而DecorView继承自FrameLayout;

mDecor = generateDecor(-1);
    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());
    }

2.generateLayout(mDecor);它主要是生成一个布局,我们以screen_simple为例。

mContentParent = generateLayout(mDecor);
<!--screen_simple.xml-->
<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>

在generateLayout中它会创建一个ViewGroup,而它的id就是content

    /**
     * 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;

  ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

最后将contentParent返回给mContentParent。我们回到PhoneWindow的setContentView方法

 mLayoutInflater.inflate(layoutResID, mContentParent);

此处把我们MainActivity中的R.layout.activity_main加入了mContentParent中。

总结:
1、创建顶层布局容器DecorView;
2、在顶层布局中加载基础布局ViewGroup;
3、将setContentView添加到基础布局中的FrameLayout中。
类关系和视图结构如下:


image.png

相关文章

网友评论

      本文标题:UI绘制流程及原理(一)

      本文链接:https://www.haomeiwen.com/subject/sodiectx.html