UI核心 - UI绘制流程及原理

1. View添加到屏幕窗口的源码分析

入口:在Activity的onCreate中调用setContentView传入布局资源ID。

接着调用 :getWindow().setContentView(layoutResID);

其中 getWindow,返回就 Window 的唯一实现类 PhoneWindow。

java 复制代码
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

PhoneWindow:

java 复制代码
    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            ...
        }
        ...
    }
java 复制代码
    private void installDecor() {
        if (mDecor == null) {
            mDecor = generateDecor(-1); // return new DecorView 
           ...
        } else {
            ...
        }
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);
            ...
        }
    }

在 PhoneWindow 的 setContentView 中,会调用 installDecor 里面的方法执行 generateDecor 创建 DecorView。

DecorView继承自FrameLayout,是应用窗口的顶层View容器。

然后将 mDecor 传进 generateLayout,

该方法根据系统主题属性(如是否有ActionBar、浮动窗口等)确定不同的layoutResource(例如R.layout.screen_simple)。

通过 mDecor.onResourcesLoaded(mLayoutInflater, layoutResource); 将得到的布局资源添加到 DecorView 中。

然后通过 findViewById 获取 id 为 com.android.internal.R.id.content 的基础布局,一般为 FrameLayout,后面我们的界面就是绘制在这个布局里面的。

最终返回这个 contentParent

小结

PhoneWindow持有DecorView。DecorView中包含根据主题生成的基础布局(如screen_simple),该基础布局通常包含标题栏(Title/ActionBar)和内容区域(ID为content的FrameLayout)。我们的XML布局最终被添加到这个content容器中。

2. View绘制流程的触发机制

绘制的入口是ActivityThread的handleResumeActivity方法。

该方法在执行performResumeActivity(回调onResume)后,初始化WindowManager.LayoutParams,并调用WindowManager的addView方法。

WindowManager 来源:

  • Activity中的WindowManager接口实现类为WindowManagerImpl。
  • WindowManagerImpl的addView方法委托给WindowManagerGlobal的addView方法。
  • WindowManagerGlobal.addView中创建ViewRootImpl对象,并将DecorView、布局参数等与之关联。

关键调用:root.setView(view, wparams, panelParentView),其中root即为ViewRootImpl实例。

3. 绘制核心流程:PerformTraversals

在ViewRootImpl.setView中调用requestLayout()。该方法首先通过checkThread()确保当前操作在主线程执行,随后调用scheduledTraversals()。

scheduledTraversals()通过Choreographer(编舞者) post一个TraversalRunnable。当VSync信号到来时,TraversalRunnable的run方法被执行,进而调用doTraversal()。

doTraversal()的核心是调用performTraversals()。在此方法中,依次执行UI绘制的三个关键步骤:

  • 测量 (Measure):调用performMeasure(),确定View的大小。
  • 布局 (Layout):调用performLayout(),确定View的位置。
  • 绘制 (Draw):调用performDraw(),将View内容渲染到屏幕上。
相关推荐
大蓝头6 天前
安装包UI美化之路-nsNiuniuSkin全新UI调试与预览方法
ui·electron·安装包·截图控件·截屏控件
慧都小项6 天前
当边缘AI上产线:QtitanDocking 如何让工业 HMI 实现多视图协同
人工智能·qt·ui·边缘计算·qt6.3
兰亭妙微UI设计公司7 天前
兰亭妙微UI设计公司分享:EQUA 智能健康生态系统 UI/UX 设计深度解析
ui·交互
Cx330❀7 天前
Qt 常用控件属性与底层机制详解:从窗口半透明、浮点数陷阱到 QSS 与焦点策略
qt·ui·图形渲染
Cx330❀7 天前
Qt 常用 UI 控件详解:从QPushButton到QLabel 核心用法解析
qt·ui·图形渲染
传奇开心果编程8 天前
【ArkUI 练中学】第15课:UI 界面设计与实战
学习·ui·华为·harmonyos
HwJack208 天前
【HarmonyOS开发小实践】ArkUI 动画系统属性动画、显式动画与路径动画
ui·性能优化·harmonyos
传奇开心果编程8 天前
【Flutter入门练中学】第2课:布局系统
学习·flutter·ui
传奇开心果编程8 天前
【Jetpack Compose基础语法学与练】第8课 rememberSaveable,页面旋转/系统重建保留状态
android·学习·ui·kotlin·android jetpack