折纸
你已经会一半了。剩下的一半,在那棵你看不见的树上。
你写过 Compose,知道界面是状态的函数,知道要把 UI 描述出来而不是命令它改。这些直觉一条都不用扔——Flutter 和 Compose 是一对表兄弟,连 Column 和 Row 都同名。
但你也做过一点 Flutter,然后被一些说不清的事绊过:交换两个卡片,颜色没跟着走;随手包了一层 Padding,动画重来了一遍;把 ListView 放进 Column,App 当场红屏。这些不是零散的坑,它们全是同一件事的不同侧面——你还没见过那棵框架真正在维护的树。
一句话说清这本书:你每一帧写下的只是一张平摊的纸——一份不可变的界面配置说明书,写完就被扔掉。框架照着上一帧留下的折痕,把这张新纸折成真正会量尺寸、会画像素的东西。
纸是一次性的(Widget),折痕是长命的(Element),折出来的立体物才是你在屏幕上看见的(RenderObject)。Compose 把折痕藏进了编译器插件和 slot table,Flutter 把它摆到了桌面上,还让你亲手管它——const、Key、BuildContext,全是管折痕的工具。学完这本书你会发现一件意外的事:Compose 你原来也才懂一半。
直觉清关表
这本书不假装你是新手。每一章开头都会拎出一条你从 Compose 带过来的直觉,当场盖章:直接放行、改一下、还是得扔掉。24 章 24 条,结果是这样的——
主线一:三棵树。Widget 为什么可以每帧扔掉?State 凭什么活得下来?canUpdate 只看 runtimeType 和 key 这两个字段——一旦你接受这句话,Key 的坑、动画重来的坑、热重载为什么保得住状态、const 为什么是性能开关,会在同一秒钟一起讲通。
主线二:范围是谁划的。Compose 有编译器插件替你划重组范围,读了哪个状态就订阅哪个 scope,细到一个 Text。Flutter 没有这个编译器——setState 把整棵子树从那个 Element 往下重建一遍。于是「缩小重建范围」从编译器的工作,变成了你的手艺:拆 widget、加 const、把 Consumer 放到最小的那一块上。这本书后半本一直在讲这件手艺。
目录
时间紧、下周就要开工:读卷 II(6–9 章)和卷 III(10–12 章),这七章解决你在 Flutter 里 80% 的「说不清为什么」。然后直接跳到卷 VI 抄工程骨架。
只想把印象加深:按顺序读,每章开头的那枚印章就是这一章的全部结论,正文是它的展开。
Demo 别只看:17 个 Demo 全是真跑的引擎——第 6 章那台会真的执行 Flutter 的 updateChild 算法,第 10 章那台会真的传播 BoxConstraints 并算出 RenderFlex overflowed by 500 pixels 这样的报错。正文里出现的每个数字,都是它们当场算的。