一、绘制过程
我们知道 Widget
最终都转化为 RenderObject
, 所以了解绘制我们直接先看 RenderObject
的 paint
方法。
如下图所示,所有的 RenderObject
子类都必须实现 paint
方法,并且该方法并不是给用户直接调用,需要更新绘制时,你可以通过 markNeddsPaint
方法去触发界面绘制。
那么,按照“国际流程”,在经历大小和布局等位置计算之后,最终 paint
方法会被调用,该方法带有两个参数: PaintingContext
和 Offset
,它们就是完成绘制的关键所在,那么相信此时大家肯定有个疑问就是:
PaintingContext
是什么?Offset
是什么?
通过飞速查阅源码,我们可以首先了解到有 :
-
PaintingContext
的关键是 A place to paint ,同时它在父类ClipContext
是包含有Canvas
,并且PaintingContext
的构造方法是@protected
,只在PaintingContext.repaintCompositedChild
和pushLayer
时自动创建。 -
Offset
在paint
中主要是提供当前控件在屏幕的相对偏移值,提供绘制时确定绘制的坐标。
OK,继续往下走,那么既然 PaintingContext
叫 Context ,那它肯定是存在上下文关系,那它是在哪里开始创建的呢?
通过调试源码可知,项目在 runApp
时通过 WidgetsFlutterBinding
启动,而在以前的篇幅中我们知道, WidgetsFlutterBinding
是一个“胶水类”,它会触发 mixin 的 RendererBinding
,如下图创建出根 node 的 PaintingContext
。
好了,那么Offset
呢?如下图,对于 Offset
的传递,是通过父控件和子控件的 offset 相加之后,一级一级的将需要绘制的坐标结合去传递的。
目前简单来说,通过 PaintingContext
和 Offset
,在布局之后我们就可以在屏幕上准确的地方绘制会需要的画面。
1、测试绘制
这里我们先做一个有趣的测试。
我们现在屏幕上通过 Container
限制一个高为 60 的绿色容器,如下图,暂时忽略容器内的 Slider
控件 ,我们图中绘制了一个 100 x 100 的红色方块,这时候我们会看到下图右边的效果是:纳尼?为什么只有这么小?
事实上,因为正常 Flutter 在绘制 Container
的时候,AppBar
已经帮我们计算了状态栏和标题栏高度偏差,但我们这里在用 Canvas
时直接粗暴的 drawRect
,绘制出来的红色小方框,左部和顶部起点均为0,其实是从状态栏开始计算绘制的。
那如果我们调整位置呢?把起点 top 调整到 300,出现了如下图的效果:纳尼?红色小方块居然画出去了,明明 Container
只有绿色的大小。
其实这里的问题还是在于 PaintingContext
,它有一个参数是 estimatedBounds
,而 estimatedBounds
正常是在创建时通过 child.paintBounds
赋值的,但是对于 estimatedBounds
还有如下的描述:原来画出去也是可以。
The canvas will allow painting outside these bounds.
The [estimatedBounds] rectangle is in the [canvas] coordinate system.
所以到这里你可以通俗的总结, 对于 Flutter 而言,整个屏幕都是一块画布,我们通过各种 Offset
和 Rect
确定了位置,然后通过 PaintingContext
的Canvas
绘制上去,目标是整个屏幕区域,整个屏幕就是一帧,每次改变都是重新绘制。
2、RepaintBoundary
当然,每次重新绘制并不是完全重新绘制 ,这里面其实是存在一些规制的。
还记得前面的 markNeedsPaint
方法吗 ?我们先从 markNeedsPaint()
开始, 总结出其大致流程如下图,可以看到 markNeedsPaint
在 requestVisualUpdate
时确实触发了引擎去更新绘制界面。
接着我们看源码,如源码所示,当调用 markNeedsPaint()
时,RenderObject
就会往上的父节点去查找,根据 isRepaintBoundary
是否为 true,会决定是否从这里开始去触发重绘。换个说法就是,确定要更新哪些区域。
所以其实流程应该是:通过isRepaintBoundary
往上确定了更新区域,通过 requestVisualUpdate
方法触发更新往下绘制。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
总结:
各行各样都会淘汰一些能力差的,不仅仅是IT这个行业,所以,不要被程序猿是吃青春饭等等这类话题所吓倒,也不要觉得,找到一份工作,就享受安逸的生活,你在安逸的同时,别人正在奋力的向前跑,这样与别人的差距也就会越来越遥远,加油,希望,我们每一个人,成为更好的自己。
-
BAT大厂面试题、独家面试工具包,
-
资料包括 数据结构、Kotlin、计算机网络、Framework源码、数据结构与算法、小程序、NDK、Flutter,
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算**