Flutter完整开发实战详解(九、 深入绘制原理)

通过调试源码可知,项目在 runApp 时通过 WidgetsFlutterBinding 启动,而在以前的篇幅中我们知道, WidgetsFlutterBinding 是一个“胶水类”,它会触发 mixinRendererBinding ,如下图创建出根 node 的 PaintingContext

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

好了,那么Offset 呢?如下图,对于 Offset 的传递,是通过父控件和子控件的 offset 相加之后,一级一级的将需要绘制的坐标结合去传递的。

目前简单来说,通过 PaintingContextOffset ,在布局之后我们就可以在屏幕上准确的地方绘制会需要的画面。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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 而言,整个屏幕都是一块画布,我们通过各种 OffsetRect 确定了位置,然后通过 PaintingContextCanvas 绘制上去,目标是整个屏幕区域,整个屏幕就是一帧,每次改变都是重新绘制。

2、RepaintBoundary

当然,每次重新绘制并不是完全重新绘制 ,这里面其实是存在一些规制的。

还记得前面的 markNeedsPaint 方法吗 ?我们先从 markNeedsPaint() 开始, 总结出其大致流程如下图,可以看到 markNeedsPaintrequestVisualUpdate 时确实触发了引擎去更新绘制界面。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

接着我们看源码,如源码所示,当调用 markNeedsPaint() 时,RenderObject 就会往上的父节点去查找,根据 isRepaintBoundary 是否为 true,会决定是否从这里开始去触发重绘。换个说法就是,确定要更新哪些区域。

所以其实流程应该是:通过isRepaintBoundary 往上确定了更新区域,通过 requestVisualUpdate 方法触发更新往下绘制。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

并且从源码中可以看出, isRepaintBoundary 只有 get ,所以它只能被子类 override ,由子类表明是否是为重绘的边缘,比如 RenderProxyBoxRenderViewRenderFlowRenderObjectisRepaintBoundary 都是 true。

所以如果一个区域绘制很频繁,且可以不影响父控件的情况下,其实可以将 override isRepaintBoundary 为 true。

3、Layer

上文我们知道了,当 isRepaintBoundary 为 true 时,那么该区域就是一个可更新绘制区域,而当这个区域形成时, 其实就会新创建一个 Layer

不同的 Layer 下的 RenderObject 是可以独立的工作,比如 OffsetLayer 就在 RenderObject 中用到,它就是用来做定位绘制的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

同时这也引生出了一个结论:不是每个 RenderObject 都具有 Layer 的,因为这受 isRepaintBoundary 的影响。

其次在 RenderObject 中还有一个属性叫 needsCompositing ,它会影响生成多少层的 Layer ,而这些 Layer 又会组成一棵 Layer Tree 。好吧,到这里又多了一个树,实际上这颗树才是所谓真正去给引擎绘制的树。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

到这里我们大概就了解了 RenderObject 的整个绘制流程,并且这个绘制时机我们是去“触发”的,而不是主动调用,并且更新是判断区域的。 嗯~有点 React 的味道!

二、Slider 控件的绘制实现

前面我们讲了那么多绘制的流程,现在让我们从 Slider 这个控件的源码,去看看一个绘制控件的设计实现吧。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

整个 Slider 的实现可以说是很 Flutter 了,大体结构如下图。

_RenderSlider 中,除了 手势动画 之外,其余的每个绘制的部分,都是独立的 Component 去完成绘制,而这些 Component 都是通过 SliderThemeSliderThemeData 提供的。

巧合的是,SliderTheme 本身就是一个 InheritedWidget 。看过以前篇章的同学应该会知道, InheritedWidget 一般就是用于做状态共享的,所以如果你需要自定义 Slider ,完成可以通过 SliderTheme 嵌套,然后通过 SliderThemeData 选择性的自定义你需要的模块。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

并且如下图,在 _RenderSlider 中注册时手势和动画,会在监听中去触发 markNeedsPaint 方法,这就是为什么你的触摸能够响应画面的原因了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

同时可以看到 _SliderRender内的参数都重写了 getset 方法, 在 set 时也会有 markNeedsPaint() ,或者调用 _updateLabelPainter 去间接调用 markNeedsLayout

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

至于 Slider 内的各种 Shape 的绘制这里就不展开了,都是 Canvas 标准的 pathTodrawRecttranslatedrawPath等熟悉的操作了。

自此,第九篇终于结束了!(///▽///)

资源推荐

  • Github : github.com/CarGuo/
  • 开源 Flutter 完整项目:github.com/CarGuo/GSYG…
    自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

学习分享

在当下这个信息共享的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了

很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘

如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。

2021最新上万页的大厂面试真题

七大模块学习资料:如NDK模块开发、Android框架体系架构…

只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。

这份体系学习笔记,适应人群:
**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。
**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。
**第三,**到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。

由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示 。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

多,篇幅不允许,部分未展示内容以截图方式展示 。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值