当前位置: 首页 > news >正文

Android UI界面绘制

Android UI绘制从 ViewRootImplperformTraversals() 方法开始,按照 测量(Measure) ->布局(Layout) -> 绘制(Draw) 的顺序,并从顶级View(DecorView)开始,递归地遍历整个View树,从而完成界面的测量、布局和最终绘制。

详细流程解析

第一步:绘制的发起者 - ViewRootImpl

ViewRootImpl 是连接WindowManager和DecorView的桥梁,它是整个绘制流程的总调度中心。
它的核心方法是 performTraversals() 。这个方法会根据需要依次执行三个关键操作:

  1. performMeasure() - 测量
  2. performLayout() - 布局
  3. performDraw() - 绘制

第二步:执行完整的绘制遍历 - performTraversals()

这是最核心的一步,它按顺序触发:
1、Measure (测量)

  1. 调用 performMeasure(int widthMeasureSpec, int heightMeasureSpec)
  2. 从DecorView开始,递归地调用所有子View的measure()方法,从而确定每个View的期望尺寸。
  3. 测量规格MeasureSpec由父View传递给子View,是父View的要求和子View的LayoutParams共同作用的结果。
  4. 关键方法
View.java
public final void measure(int widthMeasureSpec, int heightMeasureSpec);
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec);
------------------------------------------------------------------------------
ViewGroup.java中没有这两个方法。
  1. 方法调用
measure方法 (final修饰,不允许子类重写)->onMeasure方法->setMeasuredDimension方法->setMeasuredDimensionRaw方法

最终完成View的测量,将测量宽、高保存到View类的成员变量mMeasuredWidth和mMeasuredHeight。其中宽、高可以通过getMeasuredWidth()和getMeasuredHeight()方法获取得到。
2、Layout (布局)

  1. 调用 performLayout(boolean changed, int left, int top, int right, int bottom)
  2. 同样从DecorView开始,递归地调用所有子View的layout(int l, int t, int r, int b)方法。
  3. 父View会根据刚刚测量得到的尺寸,来确定每个子View在屏幕上的具体位置(四个顶点的坐标)。
  4. 关键方法
ViewGroup.java
public final void layout(int l, int t, int r, int b);
protected abstract void onLayout(boolean changed,int l, int t, int r, int b);
--------------------------------------------------------------------------
View.java
public void layout(int l, int t, int r, int b);
protected void onLayout(boolean changed, int left, int top, int right, int bottom);

3、Draw (绘制)

  1. 调用 performDraw()
  2. 这个方法会最终调用 draw(boolean fullRedrawNeeded)。
  3. 绘制流程同样递归进行。它不直接调用View的draw()方法,而是通过硬件加速或软件绘制的方式来进行:
    硬件加速(默认):draw()方法会构建并记录一系列的绘制指令(DisplayList),然后将这些指令同步给RenderThread线程。由RenderThread在GPU上真正执行这些指令,将内容渲染到屏幕上。
    软件绘制:直接调用View的draw(Canvas canvas)方法,在CPU上利用CanvasAPI一步步将内容绘制到Bitmap上,最终再将Bitmap提交给SurfaceFlinger。

常见问题

  1. 自定义View继承ViewGroup:必须重写onLayout方法。
  2. 当UI需要更新时(例如:你调用了View的invalidate()、requestLayout()、或者有动画在进行),最终都会触发ViewRootImpl的 scheduleTraversal() 方法。这个方法会通过Choreographer安排一个任务,在下一个VSYNC信号到来时执行doTraversal(),继而调用performTraversals()。
  3. View的invalidate()方法不会触发 View 的测量(measure)或布局(layout)流程,它只会标记一个脏区域,并在下一个绘制周期中仅触发重绘(Draw)流程。
  4. View的requestLayout()通常会触发测量(Measure)和布局(Layout)流程,并且有很高的概率会触发重绘(Draw)流程,但这并不是绝对的。
  5. 自定义View是否必须重写onMeasure、onLayout方法?
方法继承ViewGroup继承View
onMeasure方法必须重写必须重写
onLayout方法必须重写不需要重写
http://www.dtcms.com/a/345117.html

相关文章:

  • AI赋能体育训练突破:AI动作捕捉矫正精准、战术分析系统提效率,运动员破瓶颈新路径
  • AI计算提效关键。自适应弹性加速,基于存算架构做浮点运算
  • 自学嵌入式第二十五天:数据结构-队列、树
  • JavaWeb前端05(Vue工程化,Vue组件两种风格:组合式API 和 选项式API)及简单案例)
  • 文件下载和文件上传漏洞
  • FTP/TCP上传下载文件
  • C++ 判断: 深度解析与实战指南
  • 华中产业带跨境电商进阶:亚马逊加速器驱动下的多维度能力重构
  • CSS @media 媒体查询
  • Python从入门到自动化运维
  • 凌霄飞控开发日志兼新手教程——基础篇:认识基本的文件内容和相关函数作用(25电赛备赛版)
  • Quarkus 从入门到精通完整指南Q
  • Python socket远程部署工具服务
  • 云原生作业(k8s总结)
  • 爬虫基础学习-配置代理、以及项目实践
  • Spring Cloud系列—SkyWalking告警和飞书接入
  • CGI-CVE-2016-5385
  • 【实时Linux实战系列】实时网络流量监测与管理
  • tauri配置允许执行eval脚本,在打包cocos游戏web/phone移动端的时候一定要配置
  • canvas绘制图片等比缩放
  • 高边开关+BUCK+MOSFET:48V智能汽车动力链的“黄金三角”
  • Prometheus+Grafana监控mysql
  • AI推理革命:从Sequential Thinking到Agentic AI的演进之路——揭秘大语言模型思维进化的四重奏
  • 【Linux网络编程】Reactor反应堆模式
  • 氙灯市场报告:亚太成增长主力,汽车、医疗、科研多领域需求驱动行业发展
  • 永磁同步电机无速度算法--基于跟踪观测器的脉振正弦注入法
  • 无线数传模块实现:焦化厂四大车与除尘系统无线通讯连锁控制方案案例
  • ComfyUI 原生 REST API 技术文档
  • 视频拼接融合技术:打造全景视界的革命性产品
  • modbus绑定变量,并发送8位数据的办法