跳到主要内容

Fultter

学习日志

基础概念的笔记大多摘自第二版序 | 《Flutter实战·第二版》 为什么需要再copy一遍?

  • 自己用心cv的笔记才能记得住🐶
  • 遇到一些疑惑可以手敲代码或查阅资料后进行标注
  • 后续开发时在自己的笔记中查找要更快一些

创建一个基本实例

基于项目根目录的 lib/main.dart:

import 'package:flutter/material.dart'; // 1. 引入控件

void main(List<String> args) { // 2.程序入口
runApp(
MaterialApp( // 应用
home: Home() // 主页
)
); // 启动应用
}

class Home extends StatelessWidget {
// demo1 文本控件

Widget build(BuildContext context) {
return const Text('Hello World',
style: TextStyle(
fontSize: 30.0,
color: Colors.blue,
)
);
}
}
  1. Material (opens new window)是一种标准的移动端和web端的视觉设计语言, Flutter 默认提供了一套丰富的 Material 风格的UI组件。
  2. Flutter 应用中 main 函数为应用程序的入口。main 函数中调用了runApp 方法,它的功能是启动Flutter应用。runApp它接受一个 Widget参数,在本示例中它是一个MaterialApp对象,是 Flutter 应用的根组件。

重点概念

StatefulBuilderBuilder

  • 使用Builder来获取一个合适的上下文,特别是在需要一个特定的祖先widget的上下文时。
  • 使用StatefulBuilder来在无状态的widget中引入局部状态管理,特别是在对话框或临时UI结构中,这样你就不需要将整个widget转换为StatefulWidget
// `Builder`主要用于获得正确的上下文,特别是当你需要的上下文与当前上下文不同时,比如在`Scaffold`中使用`context`来显示`SnackBar`时
// `Builder`提供了一个新的上下文,用于`ScaffoldMessenger.of(context)`来找到最近的`Scaffold`祖先
Builder(
builder: (BuildContext context) {
return ElevatedButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Hello from Builder'),
));
},
child: Text('Show SnackBar'),
);
},
)

// StatefulBuilder 可以在一个无状态的widget中引入局部的状态管理。这对于在无状态的对话框或底部表单中添加状态非常有用,而不必将整个widget转换为`StatefulWidget`。
// `StatefulBuilder`提供了一个`setState`函数,你可以使用它来更新局部状态(在这个例子中是复选框的选中状态),并且只重建包含在`StatefulBuilder`中的widget,而不是整个对话框
showDialog(
context: context,
builder: (BuildContext context) {
bool isChecked = false;

return StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return AlertDialog(
title: Text('StatefulBuilder Example'),
content: CheckboxListTile(
value: isChecked,
title: Text('Check me!'),
onChanged: (bool? value) {
setState(() {
isChecked = value!;
});
},
),
actions: <Widget>[
TextButton(
child: Text('OK'),
onPressed: () => Navigator.of(context).pop(),
),
],
);
},
);
},
);

常见需求QA

撑满宽度,就像div那样

  1. width设置为double.infinity可以让一个widget尝试填充其父widget提供的最大宽度: body: Container(color: Colors.blue, width: double.infinity, height: 50)
  2. width设置为MediaQuery.of(context).size.width
  3. Expanded控件包裹目标控件

Xcode模拟器失败Unable to boot the Simulator.

Open Xcode -> Preferences -> Locations -> Derived Data (Click the little arrow) -> Delete the folder. 打开该目录删除,通过xcode启动模拟器后,再用vscode连接模拟器

this.$forceUpdate()

在调用setState方法后StatefulWidget就会重新build,那setState方法做了什么呢?我们能不能从中找到方法?顺着这个思路,我们就得看一下setState的核心源码:

void setState(VoidCallback fn) {
... //省略无关代码
_element.markNeedsBuild();
}

markNeedsBuild 是 Flutter 框架内部使用的一个方法,用于标记一个 Widget 需要重建(重新构建)。当一个 widget 的状态改变时(通常是在状态管理中,如使用 setState 方法后),Flutter 会将该 widget 标记为 "需要重建"。在下一个动画帧时,Flutter 会重建所有被标记的 widget,以确保它们反映最新的状态:

// 在StateLessWidget中的AlertDialog中添加需要更新UI状态的Checkbox (该方法并非最优,推荐使用StatefulBuilder)
AlertDialog(
title: Text("提示"),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text("您确定要删除当前文件吗?"),
Row(
children: <Widget>[
Text("同时删除子目录?"),
Checkbox( // 依然使用Checkbox组件
value: _withTree,
onChanged: (bool value) {
// 此时context为对话框UI的根Element,我们
// 直接将对话框UI对应的Element标记为dirty
(context as Element).markNeedsBuild();
_withTree = !_withTree;
},
),
],
),
],
)