Android UI制作流程

环境

  • Java 11
  • android 11

因为学习的课程api 不一致 导致源码有些关键办法无法进入仔细阅读 采用截图的办法理解思路

view添加到窗口

进入到源码中能够发现 ,每个activity 默许生成的代码中都会有一个setContentView办法,这个办法用于加载输入路径当前的布局以及后续的操作

底层本质仍是调用一个托付去设置资源

 @Override
  public void setContentView(@LayoutRes int layoutResID) {
    initViewTreeOwners();
    getDelegate().setContentView(layoutResID);
   }

在持续走进这个托付类的接口完结办法

Android UI绘制流程

  @Override
  public void setContentView(int resId) {
    ensureSubDecor();
    ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
    contentParent.removeAllViews();
    LayoutInflater.from(mContext).inflate(resId, contentParent);
    mAppCompatWindowCallback.getWrapped().onContentChanged();
   }
​

ensureSubDecor() 进入这个decor 办法 下图为部分代码

   if (!mSubDecorInstalled)
   mSubDecor = createSubDecor();

createSubDecor() 依据实装值 来判别是否创立对应的decor

Android UI绘制流程

这个办法中有大量的体系资源整合 ,都是一些体系主题的装修器放入到对应需求创立的window中,比方

  • content
  • themedContext
  • subDecor 等等体系资源

再持续往下看 会看到一个赋值操作 将 mWindow.setContentView(subDecor);赋值,

PS: WINDOW 目标的主要完结都在phone window 中 所以咱们去phone window 寻觅这个主要的办法

这个办法有两个主要完结 这儿咱们主要看 layouResId为参数的完结内容

  @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;
   }
​

Android UI绘制流程

这儿咱们点进 generateLayout 办法,见名知意 这个办法主要是组装布局需求的主题属性和样式属性 这儿看到

 mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);

加载资源的办法 依据不同的 feature 给layout赋不同的值,之后将布局信息添加到 mdecor

之后再 generateLayout() 回来一个 contentParent 也便是一个viewGroup

流程图

Android UI绘制流程

总结

Android UI绘制流程

  1. 在进入到activity 之后 会优先创立顶层布局 decorView 来设置体系需求的主题参数
  2. 将decorView 添加到根底布局中 回来 viewGroup 不同的主题加载不同的viewGroup 但是都会有一个容器OnDraw的id
  3. 最后被setContentView添加到布局中

View的制作流程

Android UI绘制流程

依据上图 咱们能够先去检查ActivityThread 找到 H这个类 他承继自 handle 内部完结了一个handleMessage办法 内部会有一个调用链路

  1. handleMessage 调用 handleLaunchActivity 标识 启动一个挑选的activity
  2. handleLaunchActivity 调用 handleResumeActivity
  3. handleResumeActivity 调用performResumeActivity终究在这个办法回调

Android UI绘制流程

需求留意的是在这个调用链路中 viewRootImpl performTraversal() 这个办法 ,制作view的三个步骤便是在这个线程中完结的

Android UI绘制流程

Android UI绘制流程

Android UI绘制流程

丈量

Android UI绘制流程

从最底层源码的丈量能够看出 履行丈量其实便是不断调用到最低层的 setMeasureDimensionRow 中对两个成员变量标记赋值,保存丈量控件的宽高。

在view 制作之前 安卓底层会先去使用 measure丈量对应view 的形式和尺度,安卓给咱们供给了一个叫做 measurespec类 是一个三十二位int的存储值,前两位代表形式,后三十位代表尺度

  • SpecMode(前两位) + SpecSize(后三十位)

核心办法

makeMeasureSpec

Android UI绘制流程

用于取值 mode 只需求取前两位 size 只需求取后三十位 组合成一个 MeasureSpec

相同 MeasureSpec 也有对应的getsizegetmode 获取对应的值

getRootMeasureSpec

参数

  1. 子容器高度/宽度
  2. 尖端容器 高度/宽度

依据设置的布局属性 来设置对应的mode

Android UI绘制流程

Android UI绘制流程

协助 performMeasure 是拿到需求的 measurespec

Android UI绘制流程

decor view 承继自 framelayout 检查他的 onMeasure 办法

通过递归的办法 判别并且设置不同规则父容器和子控件的丈量办法

Android UI绘制流程

View 丈量的对比图

Android UI绘制流程

完整丈量自身流程

Android UI绘制流程

Android UI绘制流程

ps: 在自定义view 的时候 一定要重写 onmeasureDiemsion办法

在 view 设置丈量自己之前会调用getdefaultsize 依据不同的形式获取到size 有趣的是 at 和 exactly 赋值都是父容器剩余的大小,所以在自定义view 需求重写一系列办法否则就可能出现问题

Android UI绘制流程

自定义容器和viwe 区别 :

  1. 自定义容器需求先丈量子控件再量自己
  2. view 直接丈量自己即可

布局

Android UI绘制流程

核心办法

view.setFrame()

Android UI绘制流程

对控件的上下左右赋值 设置完结 控件需求摆放的方位就确定了

view.onlayout()

如果此刻是容器 则需求调用此办法 确定子控件的方位

制作

Android UI绘制流程

核心办法

view.draw()

    /*
     * Draw traversal performs several drawing steps which must be executed
     * in the appropriate order:
     *
     *    1. Draw the background
     *    2. If necessary, save the canvas' layers to prepare for fading
     *    3. Draw view's content
     *    4. Draw children
     *    5. If necessary, draw the fading edges and restore layers
     *    6. Draw decorations (scrollbars for instance)
     *    7. If necessary, draw the default focus highlight
     */

Android UI绘制流程

viewGroup.dispatchDraw()

Android UI绘制流程

总结

制作过程

ViewGroup

  1. 制作布景
  2. 制作自己
  3. 制作 子控件
  4. 制作远景 滚动条等

View

  1. 制作布景
  2. 调用自己的 ondraw
  3. 制作远景 滚动条等