在Flutter项目里写UI,真正拖慢节奏的往往不是业务逻辑,而是一遍又一遍敲那些结构固定的模板代码。一个StatelessWidget要先想类名,再写build方法,再补return,手一快就把括号配错了;一个带控制器的TextField写下来十几行,复制粘贴又容易带上旧页面里的状态逻辑。我认真研究过flutter snippets自动补全插件之后,效率提升非常明显:以前要敲三十秒甚至更久的样板,现在一个缩写加一个回车就出来了,而且代码风格统一,基本不会漏import。这篇东西我就把自己在VS Code里的插件选择、高频片段、自定义方法,以及踩过的一些坑整理出来,适合刚搭好Flutter开发环境的新手,也适合想把手头工程写得更快的老手。
1. Flutter项目里,代码自动补全到底在解决什么问题?
1.1 Flutter写UI的重复劳动比想象中严重
Flutter的UI是一棵Widget树,这个设计让界面表达非常灵活,但也带来了一个副作用:同样的组件结构会被反复书写。一个页面基本逃不掉Scaffold加AppBar加Container这套外壳,一个列表页反复出现ListView.builder,一个表单页里几乎每个输入框都要套上TextField、TextEditingController、FocusNode。我见过不少新人在写完两个页面之后就开始复制上一个页面的骨架,然后改类名、改标题、换变量,一旦复制漏了某个状态清理逻辑,后面排查就要花很长时间。
这种重复劳动不只是浪费时间,更大的问题是打断心流。你脑子里想的本来是“这个页面要展示哪些数据”,结果手却一直在处理Widget嵌套、括号配对、缩进对齐这些和业务无关的事情。snippets自动补全插件解决的就是这个痛点:把结构固定、变化很少的代码片段做成模板,用短短几个字母触发,让手速跟得上思路,也让代码的格式始终保持一致。
1.2 snippets不等于IntelliSense,二者定位完全不同
很多刚开始用VS Code的读者会把两件事混在一起:一个是输入过程中弹出来的智能提示,也就是IntelliSense,另一个是输入简写后整段展开的代码片段,也就是snippets。智能提示是根据上下文猜测你接下来可能输入的符号,IDE本身就能提供,比如你输入Container它会提示构造函数参数;而snippets是预先定义好的代码模板,靠prefix里的缩写来触发,比如我输入stful后按回车,编辑器直接生成一个完整的StatefulWidget类。
理解这个区别很重要,因为涉及配置的时候,很多人明明装好了插件,却发现“自动补全不生效”,其实问题往往是他在期待IntelliSense,却不知道snippets需要敲完一个带有特殊含义的前缀才会展开。换句话说,snippets更适合处理“我知道我要写什么,只是不想一个个字符敲”的场景。Flutter正好有大量这种场景,所以它和snippets是天然契合的。
1.3 一个好的Flutter snippets插件应该覆盖哪些场景
我判断一套Flutter snippets好不好用,主要看几个方向:
- 组件外壳类:比如StatelessWidget、StatefulWidget、Consumer、BlocBuilder这类需要完整类结构的模板,这是日常用得最多的。
- 布局骨架类:Container、Row、Column、Stack、ListView、GridView,这些组件写出来不难,但嵌套多、可选参数多,模板能帮你先搭好框架再改参数。
- 异步场景类:FutureBuilder、StreamBuilder、异步方法、Stream订阅,这类代码容易写漏取消订阅或者漏处理loading状态,模板可以把常规写法固定下来。
- 状态管理样板类:Bloc、GetX、Provider相关代码,不同团队用的库不一样,但都有大量固定模式。
- 测试代码类:Flutter测试里的
testWidgets、expect等,模板化之后写测试会更愿意动手。
一套插件不必每个方向都覆盖到完美,但你至少要清楚自己最常用的是哪几类,然后针对性选择。下面我会从工具安装开始讲,再到具体片段,最后教你怎么自己做一套贴手的模板。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 常用Flutter snippets插件的选择与安装
2.1 VS Code下先把官方Dart和Flutter插件装好
在VS Code里用Flutter,官方那套Dart和Flutter扩展是基础,这两个插件本身就自带了一批常用snippets,比如stless、stful、mounted、scaffold这类缩写。安装方式很简单:打开扩展面板,搜索“Dart”和“Flutter”,认准Dart Code团队发布的版本即可。
装完之后有一点容易被忽略:插件的snippets不是装完就立刻在所有文件里生效的,它只在Dart语言模式下才会出现。如果你打开的是一个普通文本文件或者Markdown文件,输入stful是不会有任何提示的。所以验证插件是否生效,一定要新建一个.dart文件,或者打开工程里的现有Dart文件来试。另外一个老经验是,装完插件后如果发现没反应,别急着怀疑配置,先执行一下“Developer: Reload Window”重启窗口,很多加载问题都会消失。
官方插件自带的snippets数量并不算特别多,它的策略更偏向“提供最基础的脚手架”,比如类和组件的空壳,而不是把每种Widget的完整写法都塞给你。这样做的好处是提示列表不会太乱,坏处是你需要的很多常用结构还是要自己打。所以接下来一般会再加一个第三方snippets集合。
2.2 第三方Flutter snippets集合怎么选
市面上Flutter snippets第三方插件有不少,名称和内容经常混在一起,我建议按这几个标准过滤:
- 看更新时间和维护状态。Flutter版本更迭快,空安全、新组件API这些变化都会影响片段内容,长期不更新的插件很容易生成过时代码。
- 看片段的前缀会不会和官方插件冲突。冲突本身还好,最怕的是两个插件对同一个前缀提供不同内容,弹出的提示列表里出现两条相近结果,容易选错。
- 看是否包含你实际在用的状态管理和网络库。有的插件侧重Widget模板,有的侧重Bloc/GetX,还有的偏网络层,选之前先扫一眼说明。
以“Awesome Flutter Snippets”这个扩展为例,它在VS Code里搜索量一直很高,片段覆盖比较广,从stless到bloc到dio请求都有。装的时候不要贪多,装一两个主力的就够了,装得太多会出现一个问题:同一前缀被多个插件重复注册,导致每次展开都要仔细看来源。VS Code虽然可以设置editor.snippetSuggestions为top来把片段排在提示前置位,但也架不住几十个相似项堆在一起。
2.3 Android Studio侧的选择逻辑
如果你主要的编辑器是Android Studio或者IntelliJ IDEA,思路是类似的。Flutter官方插件本身带了Live Templates,在Dart文件里输入stful、stless就会看到候选。Android Studio的Live Templates本质就是一种snippets机制,只不过它的配置入口在“Settings -> Editor -> Live Templates”里。
Android Studio用户也可以装第三方Flutter snippets插件,插件市场里同样有不少。但我的建议是,如果你团队跨编辑器协作,尽量以自定义片段为主,少依赖某个第三方插件的私有前缀,否则两个人用不同编辑器,打出来的基础代码风格可能都不一样。官方插件带的那些通用缩写基本能保证两边一致,后续再通过自定义片段来统一团队规范,这样最稳妥。
2.4 安装完要做的最小验证
装好插件之后,我会用下面这组动作做一次快速验证,避免等到写代码时才发现环境有问题:
- 打开任意一个Dart文件。
- 输入
stless,等弹窗出现,按回车。 - 确认生成的代码是完整的StatelessWidget,并带有
const构造函数。 - 再输入
stful,确认State类和createState方法都正常。 - 输入
mounted,确认会生成if (!mounted) return;这行常用保护代码。
如果第3步生成的类里没有const关键字,或者第5步没有提示,多半是Flutter版本较老或者插件版本和SDK不匹配。这时候优先做的事不是去搜一大堆配置,而是先更新插件,再检查项目使用的Flutter SDK版本是否过旧。验证完毕之后,你再开始熟悉高频片段,压力会小很多。
3. 高频Flutter代码片段拆解:从缩写到完整组件
3.1 组件外壳类:stless、stful、mounted
stless和stful是Flutter snippets里最出名的两个前缀,几乎所有插件都支持。输入stless再回车,会得到类似下面的代码:
dart复制import 'package:flutter/material.dart';
class MyWidget extends StatelessWidget {
const MyWidget({super.key});
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}
stful生成的则是StatefulWidget的标准结构,通常会自动创建State类和createState方法。这里我想提醒一点:很多人对StatefulWidget有一种误解,觉得“页面里有变化”就要用它,其实很多变化完全可以用StreamBuilder、ValueListenableBuilder或者AnimatedBuilder处理,根本不需要State。模板生成得越顺手,越要停下来想清楚这个组件到底需不需要变得“有状态”。
mounted这个前缀很多人会忽略,但它非常实用。在异步操作完成后要更新State时,标准的防御写法是if (!mounted) return;,手敲很容易漏,漏掉之后在异步回调里调用setState可能直接抛异常。把它做成snippet之后,我写异步逻辑的规范稳定了很多。
3.2 Widget骨架类:Container、Row、Column、ListView
我一开始觉得Container这种Widget没必要用snippets,直到有一次手写一个带圆角、阴影、内边距的Container,写了一半发现少了个括号,补了半天才发现还少了个逗号,从那以后就老老实实用模板。
以ListView.builder为例,一个常用的骨架是:
dart复制ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(items[index]),
);
},
)
这类片段的真正价值不只是少敲几个字,而是帮你养成写itemBuilder时把返回Widget的结构先列出来的习惯。手动敲的时候,很多人会顺手写一个return Text(...)实现完功能再说,等后面需求变成卡片布局,又要回来改结构。模板一般不限制你return什么,但会把“key、index参数已就位”这个起始状态固定下来,省了很多重复心理建设。
3.3 表单控件类:TextField、Scaffold、页面外壳
写Flutter表单是我个人觉得最需要snippets的场景。一个功能完整的输入框,要考虑TextEditingController、FocusNode、输入限制、键盘类型、错误提示。如果每次从零开始打,很容易漏掉某个属性。用snippet先把骨架铺开,再逐个填值,体验完全不一样。
dart复制TextField(
controller: _controller,
focusNode: _focusNode,
decoration: const InputDecoration(
labelText: '请输入',
border: OutlineInputBorder(),
),
)
更常见的需求是快速生成一个带AppBar、带body的Scaffold页面外壳,然后你只需要往body里填具体内容。很多snippets插件里的scaffold前缀就是干这件事的:
dart复制Scaffold(
appBar: AppBar(
title: const Text('标题'),
),
body: const Center(
child: Text('内容'),
),
)
这种模板最大的价值在于,每次生成出来脚手架都长一样,代码审阅的时候很容易扫出哪里是真正改过的。如果每个人手打的页面布局风格都不一样,review的时候反而要看半天格式。
3.4 异步与状态管理相关片段
异步在Flutter里太常见了,常见的snippet会把FutureBuilder结构铺好,包括连接状态判断和错误处理。以FutureBuilder为例:
dart复制FutureBuilder<T>(
future: _future,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
return Text('${snapshot.data}');
},
)
为什么需要把这个也模板化?因为新手很容易只写snapshot.hasData就返回内容,结果加载中状态没有占位、异常状态没有兜底,体验很差。有了模板,初始状态就是完整的,你只需要把T、_future、成功后的视图替换成实际内容。
状态管理代码也一样,比如Bloc的BlocBuilder、GetX的Obx,这类代码框架性极强,改成snippet最合适。团队里如果统一了状态管理方案,我会建议把固定的几段高频代码沉淀成自定义snippets,而不是依赖某个插件“顺便提供”的版本。这样可以完全匹配自己工程里的依赖版本和风格。
3.5 前缀命名和记忆技巧
snippets用得好不好,很大程度上取决于前缀好不好记。我的习惯是把前缀分成几类:
- 类模板类:
stless、stful、consumer、bloc。 - Widget类:直接用Widget名,比如
container、listview、textfield。 - 动作类:比如
scaffoldPage、showDialog、snackbar,用驼峰串起多个词。 - 文件类:比如
page、repository,适合生成整个文件的初始内容。
这里有个容易踩的坑:前缀越短越容易和其他插件撞车,比如dialog这种词很通用,装了好几个插件后可能弹出来五六个不同实现。这时候不建议去背各种插件的前缀表,而是趁机把所有第三方插件里不用的片段条目禁用,或者干脆用自定义snippets覆盖掉常用部分,把自己真正要用的前缀稳定下来。
4. 自己动手定制Flutter snippets自动补全
4.1 在VS Code里创建用户代码片段
现成插件不能满足你所有需求,这很正常,因为每个团队都有自己的基础设施。比如我们团队要求页面根节点必须是SafeArea加自定义容器的组合,这种约定就不可能被某个通用插件覆盖到,所以自定义片段才是解决最后一公里问题的关键。
在VS Code里创建自定义snippets的路径很直接:
- 按
Ctrl+Shift+P(macOS是Cmd+Shift+P)打开命令面板。 - 输入
Snippets: Configure User Snippets并回车。 - 在弹出的语言列表中选择
Dart,会打开一个dart.json文件。 - 在这个JSON文件里添加你自己的片段。
如果你希望一组片段在Dart之外也能用,也可以选择“New Global Snippets file”创建一个后缀为.code-snippets的全局文件,然后在片段定义里显式写"scope": "dart"。我更推荐直接在dart.json里维护,因为Flutter的片段基本只服务Dart语言,文件少一点,找起来也方便。
4.2 从一个页面模板到可复用的snippet
下面用一个我经常用的页面模板来演示。这个模板会生成一个带有AppBar的StatelessWidget页面外壳,你只需要填写类名和标题:
json复制{
"Flutter Page": {
"prefix": "fpage",
"body": [
"import 'package:flutter/material.dart';",
"",
"class ${1:PageName} extends StatelessWidget {",
" const ${1:PageName}({super.key});",
"",
" @override",
" Widget build(BuildContext context) {",
" return Scaffold(",
" appBar: AppBar(",
" title: const Text('${2:页面标题}'),",
" ),",
" body: $0",
" );",
" }",
"}"
],
"description": "创建一个带AppBar的Stateless页面外壳"
}
}
保存dart.json后,回到Dart文件输入fpage,就会看到这个模板的预览。按回车后,光标会停留在PageName这个占位符上,你直接输入类名,按Tab跳到下一个占位符,再输入标题,完成后光标会落在$0所在的位置,也就是body里等待你写内容的地方。
这个模板里有两个细节值得说。第一,占位符用${1:PageName}这种写法,第一个Tab位置就是类名,而且同一个类名会同步填到构造函数的位置,不需要改两遍。第二,最后用$0收尾,它代表片段展开完成后最终的编辑位置,这个设计很关键,否则展开完之后你还要用鼠标点回body区域,体验会差很多。
4.3 自定义片段时的三个常见坑
写自定义snippets最怕的是“写完模板,发现展开后格式是乱的”。第一个常见坑是JSON转义,body里的双引号必须转义成\",换行不能用\n拼在一个字符串里,最好一行一行地放成数组元素。比如body数组里的"return Scaffold(",前后的双引号是JSON语法,Dart代码里的字符串字面量要用\"。
第二个常见坑是缩进。VS Code本身有格式化功能,但snippet展开时是按body里的原样输出的,body里用空格还是Tab要统一。Flutter官方推荐两个空格缩进,你就照这个标准来,展开之后不需要重新整理。我发现很多新手写的body从第二行开始没有对齐,或者在数组元素里混入Tab,展开后代码乱七八糟。
第三个常见坑是片段里包含$符号。Dart的字符串插值本身就是$加花括号,而snippet语法里$是占位符的起始符号,两者撞车。如果你想生成的代码里保留${name}这种Dart插值,在片段正文里需要写成\\${name},让snippet引擎把$识别成普通字符而不是占位符。这层转义很容易把人绕晕,所以我个人的经验是:自定义片段初期尽量避开包含字符串插值的模板,只做纯结构和纯调用的片段,等熟练了再挑战带插值的复杂模板。
4.4 用占位符和Tab跳转控制生成流程
占位符是自定义snippets里最核心的交互设计。一个高质量的模板,展开之后应该像在填表:第一个Tab填最重要的参数,后续Tab按填写顺序走,而不是让你用鼠标在生成的代码里到处找位置。
常用的占位符规则:
$1、$2、$3:按Tab顺序跳转的位置,光秃秃的没有默认值。${1:default}:第二个Tab位置,带默认文本,按下Tab前可以整体选中覆盖,直接输入新值。${2|option1,option2|}:带下拉选项的占位符,适合二选一或少量固定值,比如${2|withTree,withoutTree|}。$0:片段结束后的最终光标地址,只能有一个。
我做一个自定义片段前,会先在纸上按“类名、标题、内容”的顺序草拟这张Tab跳转表。如果不排好顺序,展开后就得靠鼠标到处点,那就失去了snippets自动补全的意义。
4.5 团队共享Flutter snippets的方式
自定义snippets做到一定规模后,你会希望整个团队都用同一套,而不是各自在本地默默维护。VS Code有几种分享方式:
- 把
dart.json文件直接提交到Git仓库,让队友手动放到各自的用户目录。 - 做一个团队内部的扩展插件,把snippets打包进去,用
.vsix文件安装。 - 用VS Code的“Settings Sync”这类同步功能,与个人配置一起同步。
我的经验是,如果团队只有几个人,直接在README里放一份dart.json,让每个人复制到自己的用户配置里最省事。团队规模大了以后,建议封装成一个内部扩展,统一更新版本号,发布到内部插件市场,这样职责更清晰。无论用哪种方式,配置文件的版本管理都要做,因为片段内容会随着Flutter版本和团队规范的升级而变化,没有人维护的共享片段最终会变成一堆过时模板,反而坑人。
5. 实战中的常见问题与排查技巧
5.1 装了插件但输入缩写没反应
这个问题的出现频率比我预想的要高得多。排查时我一般按照下面这个顺序来:
- 确认当前文件是Dart文件。VS Code左下角会显示当前语言模式,如果是纯文本,snippets默认不触发。
- 确认输入的前缀完全匹配。有的片段写的是
stful,你输入stf也能看到候选,但如果你输入stfull,可能提示列表里不出现,snippets的匹配规则不是简单的模糊搜索。 - 确认没有多个插件把相同前缀覆盖成冲突状态。可以打开命令面板搜索“Snippets: Insert Snippet”,手动查看当前可用的所有片段里有没有你输入的那个。
- 重启VS Code窗口。扩展加载偶尔会卡在旧状态,这是成本最低的尝试,但很多人忘了做。
5.2 Tab键被占用,片段无法完整展开
有读者遇到过这种情况:输入fpage后能看到片段预览,但按Tab键并没有跳到下一个占位符,反倒是把焦点移到了别的地方。原因通常是有一个编辑器扩展或者系统快捷键抢先占用了Tab键。
VS Code的Tab键有着多重身份:在交互式建议里按Tab可以选择当前项,在snippet内部按Tab可以跳转到下一个占位符。如果你设置的editor.tabCompletion和某个快捷键冲突,二跳失效的情况就会出现。遇到这种问题,先检查一下有没有装类似“Tab out”的扩展,这类扩展经常会拦截Tab键。其次可以在设置里把editor.snippetSuggestions调整为top,或者把editor.tabCompletion改成on,让snippets候选排在前面。
5.3 片段展开后缩进全部乱掉
展开后的代码挤成一堆,一般不是VS Code坏了,是snippet的body本身没有做好缩进。很多人写body数组时,为了JSON文件好看,把第二行开始的元素顶到最左边,结果展开后代码就全顶格了。
JSON数组元素里,每个字符串前面的空格是会被原样保留到编辑器里的。所以body数组里每一行字符串的缩进都要自己按目标代码格式写好。Flutter的Dart代码用两个空格作为一级缩进,如果模板里有build方法下面的字节,需要自己数好空格。展开后如果还是不放心,直接按Shift+Alt+F执行Dart格式化,它会把整个文件整理好。但注意,格式化只对语法正确的代码有效,如果片段里某行的括号没有配对,格式化反而可能变乱。
5.4 片段提示太多太吵,影响写代码
Flutter插件和第三方插件装多了之后,输入任何字母都可能弹出一大串片段命名,这种干扰会让人慢慢放弃使用自动补全。解决办法不是卸载所有插件,而是做减法:
- 在插件列表里禁用不常用的第三方片段集,不要只禁用而不卸载,因为禁用后重启才会彻底生效。
- 在设置里调整
snippetSuggestions为top,让候选片段排在普通代码提示前,减少视觉噪声。 - 自己维护一个“常用前缀清单”,只记住稳定的内容,而不是每次都从候选列表里找。
我这里多说一句:snippets的价值在于“可预期”,如果你每次输入一个字母都弹出一堆不知从哪来的片段,说明这套插件组合已经不适合你了,主动清理比硬着头皮适应更重要。
5.5 热重载后浏览器没更新,别误以为是snippets问题
Flutter开发里还有一个常见的混淆场景:在VS Code里改完代码,保存后终端显示热重载了,但Chrome里的页面迟迟不更新。很多人第一反应是自动补全或者插件出了问题,其实和snippets没有任何关系。
用flutter run -d chrome跑Web项目时,热重载的体验和移动端有区别,某些改动(特别是main函数附近的结构性改动)在浏览器里不一定能立即反映出来。这时候在终端按一下R(大写)执行完整热重启,页面通常会恢复正常。如果还不行,停掉进程重新flutter run一次。我在团队里发现这个现象反复出现,已经把“先R重启再排查插件”写进了新人上手文档里。
5.6 最终排查速查表
| 问题 | 可能原因 | 快速处理 |
|---|---|---|
| 输入缩写无候选 | 非Dart文件、插件未加载、前缀不匹配 | 检查语言模式,重启窗口,手输插入片段路径 |
| Tab键不跳转 | 快捷键被扩展占用、tabCompletion配置不当 | 检查Tab相关扩展,设置tabCompletion为on |
| 展开后缩进乱 | body缩进未按目标代码排版 | 重写body数组缩进,再执行格式化 |
| 出现两个相同前缀 | 不同插件或自定义片段重复 | 禁用多余片段集,清理dart.json |
| 片段代码编译报错 | SDK版本过旧、片段过时、手动改动出错 | 更新Flutter与插件版本后重新展开 |
| 热重载后页面没更新 | Web热重载机制限制 | 终端按R热重启,再不行重新运行 |
这张表并不完整,但覆盖了我这几年遇到的绝大多数问题。遇到奇怪问题时,先想“是不是我自己配置错了”,再想“是不是插件之间打架了”,最后再怀疑“是不是Flutter工具链本身的限制”,按这个顺序排查最快。
6. 让Flutter snippets真正变成自己的生产力
6.1 先精减,再记忆
我不建议任何人一上来就疯狂收集片段,那样只会让编辑器变得更嘈杂。真正有效的做法是:先用官方插件加一个主流第三方插件跑两周,在这期间记录自己反复手敲的代码,两周之后把高频出现的内容沉淀成自己的模板。这样你最终留下的片段数量可能只有二十到三十个,但这几十个一定是你每天都在用的,熟练度会非常高。
6.2 把片段当成代码规范的载体
snippets还有一个隐藏价值,它可以成为团队代码规范的载体。比如页面必须包含AppBar标题、必须使用SafeArea、错误处理必须给用户反馈,这些规范如果只写在文档里,很容易被遗忘,但如果做成了模板,新人一用出来的代码就是规范的,代码评审的压力也能减轻很多。
从项目维护的角度看,snippets是“轻量级脚手架”。它不像代码生成器那样一次性建好整个页面,而是把你在编辑器里的每一次输入变成积累规范的过程。我甚至会把常用第三方库的调用方式也做成snippets,比如初始化网络客户端的标准写法、统一日志工具的调用方式,这样别人看我代码的时候,能明显感觉到风格的一致性。
6.3 定期迭代,不要太早固化
Flutter版本更新很快,snippets里的API也可能过时。我给自己定的习惯是,每次升级Flutter版本后,抽时间检查一遍自定义的dart.json,把不再推荐的写法替换掉。类似的,团队内部如果改了代码风格或组件库名称,也要同步更新片段。片段一旦固化并且长期没人维护,它就会从效率工具变成技术债,这一点一定要警惕。
6.4 最后分享一个我常用的判断标准
我现在写Flutter代码有一个很朴素的判断标准:如果一段代码我在项目里第三次靠复制粘贴来复用,我就会停下来,把它要么封装成一个通用Widget或者方法,要么沉淀成一个snippet。前者解决“逻辑复用”的问题,后者解决“输入效率”的问题,两者并不冲突。
比如我给自己定制的“表单输入框”片段、页面外壳片段,本质上都是为了让我不用反复去硬编码相同结构。哪怕每次只节省十几秒,但一天几十次下来,节省的不只是时间,还有注意力和耐心。如果你最近刚开始折腾flutter snippets自动补全插件,我建议你从stful和fpage这两个模板入手,先把页面骨架类的东西跑通,然后慢慢积累自己的片段库。过一个月回头看,你会发现自己写Flutter代码的节奏真的不太一样了。
