Flutter 备忘清单 === 包含 Flutter 常用的组件、布局、方法等。初学者的完整快速参考 入门 --- ### macOS 操作系统上安装和配置 ```bash $ sudo softwareupdate --install-rosetta --agree-to-license ``` 在 [Apple 芯片的 Mac 电脑](https://support.apple.com/zh-cn/HT211814) 上,还需要安装 [Rosetta 2](https://github.com/flutter/website/pull/7119#issuecomment-1124537969) 环境因为 一些辅助工具 仍然需要,通过手动运行上面的命令来安装 #### 获取 Flutter SDK - 安装包来获取最新的 stable Flutter SDK: - Intel [`flutter_macos_3.3.8-stable.zip`](https://storage.flutter-io.cn/flutter_infra_release/releases/stable/macos/flutter_macos_3.3.8-stable.zip) - Apple 芯片 [`flutter_macos_arm64_3.3.8-stable.zip`](https://storage.flutter-io.cn/flutter_infra_release/releases/stable/macos/flutter_macos_arm64_3.3.8-stable.zip) 想要获取到其他版本的安装包,请参阅 [SDK 版本列表](https://flutter.cn/docs/development/tools/sdk/releases) 页面 - 将文件解压到目标路径, 比如: ```bash $ cd ~/development $ unzip ~/Downloads/flutter_macos_3.3.8-stable.zip ``` - 配置 `flutter` 的 PATH 环境变量: ```bash $ export PATH="$PATH:`pwd`/flutter/bin" ``` - 运行 `flutter doctor` 命令 ### Windows 操作系统上安装和配置 - 点击下方的安装包,获取 stable 发行通道的 Flutter SDK 最新版本: - [flutter_windows_3.3.8-stable.zip](https://storage.flutter-io.cn/flutter_infra_release/releases/stable/windows/flutter_windows_3.3.8-stable.zip) - 要查看其他发行通道和以往的版本,请参阅 [SDK 版本列表](https://flutter.cn/docs/development/tools/sdk/releases) 页面 - 将压缩包解压,然后把其中的 `flutter` 目录整个放在你想放置 `Flutter SDK` 的路径中(例如 `C:\src\flutter`) - 更新 `path` 环境变量,在开始菜单的搜索功能键入`「env」`,然后选择 `编辑系统环境变量`。在 **`用户变量`** 一栏中,检查是否有 **`Path`** 这个条目: - 如果存在这个条目,以 `;` 分隔已有的内容,加入 `flutter\bin` 目录的完整路径。 - 如果不存在的话,在用户环境变量中创建一个新的 Path 变量,然后将 `flutter\bin` 所在的完整路径作为新变量的值 如果你不想安装指定版本的安装包。可以忽略步骤 `1` 和 `2`。从 `GitHub` 上的 `Flutter repo` 获取源代码,并根据需要,切换到指定的分支或标签 ```bash C:\src>git clone https://github.com/flutter/flutter.git -b stable ``` 基础组件 --- ### Text 样式文本 ```dart Text("Hello world", textAlign: TextAlign.left, ); Text("Hello world! I'm Jack. "*4, maxLines: 1, overflow: TextOverflow.ellipsis, ); Text("Hello world", textScaleFactor: 1.5, ); ``` ### TextStyle 指定文本显示的样式 ```dart Text("Hello world", style: TextStyle( color: Colors.blue, fontSize: 18.0, height: 1.2, fontFamily: "Courier", background: Paint()..color=Colors.yellow, decoration:TextDecoration.underline, decorationStyle: TextDecorationStyle.dashed ), ); ``` ### TextSpan 文本的一个“片段” ```dart Text.rich(TextSpan( children: [ TextSpan( text: "Home: " ), TextSpan( text: "https://flutter.dev", style: TextStyle( color: Colors.blue ), recognizer: _tapRecognizer ), ] )) ``` ### DefaultTextStyle 文本默认样式 ```dart DefaultTextStyle( // 1.设置文本默认样式 style: TextStyle( color:Colors.red, fontSize: 20.0, ), textAlign: TextAlign.start, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("hello world"), Text("I am Jack"), Text("I am Jack", style: TextStyle( inherit: false, //2.不继承默认样式 color: Colors.grey ), ), ], ), ); ``` ### 字体设置加载 - 在 asset 中声明,要先在 `pubspec.yaml` 中声明它 ```yaml flutter: fonts: - family: Raleway fonts: - asset: assets/fonts/Raleway-Regular.ttf - asset: assets/fonts/Raleway-Medium.ttf weight: 500 - asset: assets/fonts/Raleway-SemiBold.ttf weight: 600 - family: AbrilFatface fonts: - asset: assets/fonts/abrilfatface/AbrilFatface-Regular.ttf ``` - 将字体文件复制到在 `pubspec.yaml` 中指定的位置 - 使用字体 ```dart // 声明文本样式 const textStyle = const TextStyle( fontFamily: 'Raleway', ); // 使用文本样式 var buttonText = const Text( "Use the font for this text", style: textStyle, ); ``` ### ElevatedButton "漂浮"按钮 ```dart ElevatedButton( child: Text("normal"), onPressed: () {}, ); ``` ### TextButton 文本按钮 ```dart TextButton( child: Text("normal"), onPressed: () {}, ) ``` ### OutlineButton 边框阴影且背景透明按钮 ```dart OutlineButton( child: Text("normal"), onPressed: () {}, ) ``` ### IconButton 可点击的图标按钮 ```dart IconButton( icon: Icon(Icons.thumb_up), onPressed: () {}, ) ``` ### 带图标的按钮 ```dart ElevatedButton.icon( icon: Icon(Icons.send), label: Text("发送"), onPressed: _onPressed, ), OutlineButton.icon( icon: Icon(Icons.add), label: Text("添加"), onPressed: _onPressed, ), TextButton.icon( icon: Icon(Icons.info), label: Text("详情"), onPressed: _onPressed, ), ``` ### 从 asset 中加载图片 - 在工程根目录下创建一个`images目录`,并将图片 `aaa.png` 拷贝到该目录。 - 在 `pubspec.yaml` 中的 `flutter` 部分添加如下内容: ```yaml assets: - images/aaa.png ``` 注意: 由于 yaml 文件对缩进严格,所以必须严格按照每一层两个空格的方式进行缩进,此处 assets 前面应有两个空格。 - 加载该图片 ```dart Image( image: AssetImage("images/aaa.png"), width: 100.0 ); ``` Image 也提供了一个快捷的构造函数 `Image.asset` 用于从 `asset` 中加载、显示图片: ```dart Image.asset("images/aaa.png", width: 100.0, ) ``` ### 从网络加载图片 ```dart Image( image: NetworkImage( "https://avatars2.githubusercontent.com/u/20411648?s=460&v=4"), width: 100.0, ) ``` Image 也提供了一个快捷的构造函数 `Image.network` 用于从网络加载、显示图片: ```dart Image.network( "https://avatars2.githubusercontent.com/u/20411648?s=460&v=4", width: 100.0, ) ``` ### Image 参数 ```dart const Image({ ... this.width, // 图片的宽 this.height, // 图片高度 this.color, // 图片的混合色值 this.colorBlendMode, // 混合模式 this.fit,// 缩放模式 // 对齐方式 this.alignment = Alignment.center, // 重复方式 this.repeat = ImageRepeat.noRepeat, ... }) ``` ### Switch 单选开关 ```dart Switch( value: true,//当前状态 onChanged:(value){ // 重新构建页面 }, ), ``` ### Checkbox 复选框 ```dart Checkbox( value: true, // 选中时的颜色 activeColor: Colors.red, onChanged:(value){ // ... }, ) ``` ### TextField 文本输入框 ```dart TextField( autofocus: true, onChanged: (v) { print("onChange: $v"); } ) ``` ### LinearProgressIndicator 线性、条状的进度条 模糊进度条(会执行一个动画) ```dart LinearProgressIndicator( backgroundColor: Colors.grey[200], valueColor: AlwaysStoppedAnimation(Colors.blue), ), ``` 进度条显示 `50%` ```dart LinearProgressIndicator( backgroundColor: Colors.grey[200], valueColor: AlwaysStoppedAnimation(Colors.blue), value: .5, ) ``` ### CircularProgressIndicator 圆形进度条 模糊进度条(会执行一个旋转动画) ```dart CircularProgressIndicator( backgroundColor: Colors.grey[200], valueColor: AlwaysStoppedAnimation(Colors.blue), ), ``` 进度条显示 `50%`,会显示一个半圆 ```dart CircularProgressIndicator( backgroundColor: Colors.grey[200], valueColor: AlwaysStoppedAnimation(Colors.blue), value: .5, ), ``` ### 自定义尺寸 线性进度条高度指定为 `3` ```dart SizedBox( height: 3, child: LinearProgressIndicator( backgroundColor: Colors.grey[200], valueColor: AlwaysStoppedAnimation(Colors.blue), value: .5, ), ), ``` 圆形进度条直径指定为 `100` ```dart SizedBox( height: 100, width: 100, child: CircularProgressIndicator( backgroundColor: Colors.grey[200], valueColor: AlwaysStoppedAnimation(Colors.blue), value: .7, ), ), ``` 基础布局 --- ### Container 在实际开发中,Container常常用于对一个组件进行包装修饰。 ```dart Container( width: 100, height: 100, color: Colors.blue, alignment: Alignment.center, child: Text('Hello world'), ), ``` 将 `Contianer` 大小固定为 `100 * 100`, 背景色为蓝色。把 `Text` 包裹在 `Container` 中,并将其居中 ### Column 列布局(Column),可以将多个子组件沿着垂直的方向摆放(竖的摆放) ```dart // 将container 和 button 摆放到同一列。 Column( children: [ Container( width: 100, height: 100, color: Colors.blue, alignment: Alignment.center, child: Text('Hello world'), ), ElevatedButton( onPressed: () {}, child: Text('Button'), ), ], ), ``` ### Row 行布局(Row),可以将多个组件沿水平的方向摆放。 ```dart Row( children: [ ElevatedButton( onPressed: () {}, child: const Text('1'), ), ElevatedButton( onPressed: () {}, child: const Text('2'), ), ElevatedButton( onPressed: () {}, child: const Text('3'), ), ], ), ``` 在同一行摆放 3 个 `Button` ### Wrap 将子组件从左到右依次排列,当空间不足时自动换行。 ```dart Wrap( children: [ FlutterLogo(), FlutterLogo(), FlutterLogo(), FlutterLogo(), FlutterLogo(), FlutterLogo(), ], ), ``` 显示多个 `Flutter` 的 `logo` 并自动换行 ### Stack Stack 可以将一多个子组件叠在一起显示。堆叠顺序按照children属性中的列表依次堆叠摆放,默认将子控件沿左上角对齐。 需要控制子控件位置可以嵌套`Positoned`控件。 ```dart Stack( children: [ Container( height: 300, width: 300, color: Colors.blue, ), Container( height: 200, width: 200, color: Colors.black, ), Container( height: 100, width: 100, color: Colors.yellow, ), ], ), ``` 依次堆叠 `300*300` 的蓝色色块、`200*200` 的黑色色块、`100*100` 的黄色色块 ### Positioned 若需要控制Stack中子控件的位置,则可以嵌套改控件。 ```dart Stack( children: [ // 默认摆放在左上位置 Container( height: 300, width: 300, color: Colors.blue, ), // 距离左边40个、距离上面40个逻辑像素的位置 Positioned( left: 40, top: 40, child: Container( height: 200, width: 200, color: Colors.black, ), ), // 距离左边80个、距离上面80个逻辑像素的位置 Positioned( left: 80, top: 80, child: Container( height: 100, width: 100, color: Colors.yellow, ), ), ], ), ``` ### Align Align组件用于决定子组件对齐方式 ```dart // 使用Align将Button 居中在Container中 Container( width: 100, height: 100, color: Colors.green, child: Align( alignment: Alignment.center, child: ElevatedButton( onPressed: () {}, child: Text('Center'), ), ), ), ``` ### Center Center 组件实际上继承于Align。用于专门剧中。 ```dart //与 Align中代码效果一致 Container( width: 100, height: 100, color: Colors.green, child: Center( child: ElevatedButton( onPressed: () {}, child: Text('Center'), ), ), ), ``` ### Flex Flex 的用法与 `Row` 或 `Column` 类似,但只需要额外传入 `direction` 参数 - `Row` 和 `Column` 组件都继承 `Flex` 组件 - 设置 `direction` 为 `Axis.horizontal` 表示水平方向(`Row`),为 `Axis.vertical`则为垂直方向(`Column`) 垂直方向依次摆放3个flutter logo ```dart Flex( direction: Axis.vertiacl, children: [ FlutterLogo(), FlutterLogo(), FlutterLogo(), ], ), ``` 水平方向依次摆放 3 个 flutter logo ```dart Flex( direction: Axis.horizontal, children: [ FlutterLogo(), FlutterLogo(), FlutterLogo(), ], ), ``` ### Expaneded Expanded 用于扩张一个子组件。可以通过 `flex` 属性,用于表示该组件相对其他弹性组件放大的倍数(可以理解为一个权重)。 ```dart // Container 会占满剩余的全部空用空间 Row( children: [ FlutterLogo(), Expanded( child: Container( child: FlutterLogo(), color: Colors.green, ), ), FlutterLogo(), ], ), // 按照1:2 的比例分配一整行的空间 Row( children: [ Expanded( flex: 1, child: Container( child: FlutterLogo(), color: Colors.green, ), ), Expanded( flex: 2, child: Container( child: FlutterLogo(), color: Colors.blue, ), ), ], ), ``` ### Flexible `Flexible` 是 `Expanded` 组件的父类。 与 `Expanded` 不同的是,`Flexible` 可以通过 `fit` 属性设置子控件是否必须占满 `Flexibal` 扩展的空间。而 `Expaned` 默认子控件必须占满 ```dart // 如果将fit设置为tight, // 则绿色Container 和蓝色Container大小一样。 // 如果将fit设置为loose, // 则两个Flexible扩展的空间大小是一样的, // 但绿色Container并不会填充整个扩展的空间。 Row( children: [ Flexible( flex: 2, // fit: FlexFit.tight, child: Container( child: FlutterLogo(), color: Colors.green, ), ), Expanded( flex: 2, child: Container( child: FlutterLogo(), color: Colors.blue, ), ), ], ), ``` 将 `Flexible` 的 `fit` 属性设置为 `tingt`,就等价于使用 `Expanded` ### Spacer Spacer 用于在布局中留白 ```dart Row( children: [ Text('Item'), Spacer(), FlutterLogo(), ], ), ``` 例如,需要文本和图标位于一个行的两端,而中间留白时。就可以使用 `Spacer` ### ListView `ListView` 是一个支持滚动的列表组件。该组件默认支持上下滑动。 `ListView`的默认构造函数,会立即初始化`children`中的所有子`widget`,无法动态加载。 ```dart ListView( children: [ Text('1'), Text('2'), Text('3'), Text('4'), ], ), ``` 需要动态加载,则可以使用 `ListView.builder()`命名构函数。 ```dart // 动态生成4个Text ListView.builder( itemBuilder: (BuildContext context, int index) { return Text('$index'); }, itemCount: 4, ), ``` 需要在对`ListView`中的`Item`添加分割线,则可以借助`ListView.separated()`。 ```dart // separatorBuilder 函数用于在元素之间插入分割线。 // 也可以返回其他widget。该widget会被插入各个元素之间。 ListView.separated( itemBuilder: (BuildContext context, int index) { return Text('$index'); }, itemCount: 4, separatorBuilder: (BuildContext context, int index) { // 使用Divider widget 画一条粗为5,颜色为红色的线 return const Divider( height: 5, thickness: 5, color: Colors.red, ); }, ), ``` ### GridView `GridView`可将元素显示为二维网格状的列表组件,并支持主轴方向滚动。 使用GridView() 构造函数,需要传入gridDelegate和children。Flutter中已经提供了两种实现方式,分别是: - `SliverGridDelegateWithFixedCrossAxisCount()` 用于交叉轴方向固定数。 - `SliverGridDelegateWithMaxCrossAxisExtent()` 用于交叉轴方向限制最大长度。 ```dart // 使用SliverGridDelegateWithFixedCrossAxisCount GridView( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 4), children: List.generate( 8, (index) => Container( color: Colors.red[index % 8 * 100], child: Text("index $index"), )), ), // 使用SliverGridDelegateWithMaxCrossAxisExtent GridView( gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(maxCrossAxisExtent: 200), children: List.generate( 8, (index) => Container( color: Colors.red[index % 8 * 100], child: Text("index $index"), ), ), ), ``` `GridView.builder()`命名构造可以实现元素的动态加载,与`ListView.builder()`类似 ```dart GridView.builder( itemCount: 8, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 4), itemBuilder: (context, index) => Container( color: Colors.red[index % 8 * 100], child: Text("index $index"), ), ), ``` `Gridview.count()` 一个简单的构造函数,只需要传入`crossAxisCount`(交叉轴元素的个数)和`children`即可。 ```dart GridView.count( crossAxisCount: 4, // 每行固定为4个 children: List.generate( 8, (index) => Container( color: Colors.red[index % 8 * 100], child: Text("index $index"), )), ), ``` `GridView.extent()` 用于设定每个元素在交叉轴方向的最大尺寸。当程序运行在较大屏幕时通常能看到更多的元素,而不是少量元素的放大版。通过传入`maxCrossAxisExtent`,`Gridview`会根据屏幕尺寸自动选择合适的行数量。 ```dart GridView.extent( maxCrossAxisExtent: 200, children: List.generate( 8, (index) => Container( color: Colors.red[index % 8 * 100], child: Text("index $index"), )), ), ``` `GridView.count()`和GridView.extent()`可以看作GridView的语法糖。 ### PageView 使用`PageView`可以实现整屏页面滚动,默认为水平方向翻页。与`ListView`类似。 - `pageSnapping`参数可以设置滑动时`Page`停留在任意位置。 - `scrollDirection`参数设置滚动方向(默认为水平方向)。 ```dart PageView( pageSnapping: false, // 取消页面固定 scrollDirection: Axis.vertical, // 设置为垂直方向滚动 children: [ for (int i = 0; i < 4; i++) Container( color: Colors.red[i % 4 * 100], ) ], ), ``` 使用`PageView.builder()`命名构造,可以动态加载页面。与`ListView.builder()`类似。 ```dart PageView.builder( pageSnapping: false, scrollDirection: Axis.vertical, itemBuilder: (BuildContext context, int index) => Container( color: Colors.red[index % 4 * 100], ), ), ``` 另见 --- - [Dart 备忘清单](./dart.md) _(jaywcjlove.github.io)_ - [flutter 官网](https://flutter.dev) _(flutter.dev)_ - [flutter 中文开发者社区](https://flutterchina.club/) _(flutterchina.club)_