学习 Flutter (一)
1. 引言
什么是 Flutter?
Flutter 是 Google 开发的一套开源 UI 框架,主要用于构建高性能、高保真、跨平台的应用程序。使用一套 Dart 编写的代码,开发者可以同时构建适用于:
Android
iOS
Web
Windows、macOS、Linux 桌面端
嵌入式平台(如车载、IoT 设备)
Flutter 的核心特性包括:
热重载(Hot Reload):可以快速预览修改结果,提高开发效率。
自绘式渲染引擎(Skia):绕过原生控件,确保 UI 在各平台一致。
丰富的组件库(Widgets):一切皆组件,易于构建复杂界面。
灵活的布局系统:支持响应式和复杂嵌套的布局设计。
为什么选择 Flutter?
选择 Flutter 的理由主要包括以下几点:
跨平台统一开发
用一套 Dart 代码即可构建多端应用,极大节省开发和维护成本。
高性能
Flutter 拥有自己的渲染引擎,不依赖原生控件,性能接近原生,尤其适合需要高帧率渲染的场景。快速开发体验
热重载和热重启机制,加快了开发调试的迭代周期,提升开发效率。丰富的生态
Flutter 拥有大量开源插件(如 camera、http、firebase 等),支持多数主流功能的快速集成。社区支持良好
Google 官方持续更新,社区活跃度高,文档齐全,资源丰富。
本文档的目标和读者定位
文档目标
本系列文档旨在从零开始,系统性讲解 Flutter 框架的核心概念与开发实战内容。通过理论与实操结合,帮助读者完成从入门到进阶的技能成长路径。
具体目标包括:
理解 Flutter 的核心组件与布局体系
能够独立开发一个简单完整的 Flutter 应用
掌握跨平台适配、状态管理等实用技能
2. 环境准备
2.1 安装 Android Studio
下载地址与版本选择
官网地址:(最好开VPN)访问 developer.android.com/studio 或者 Android Studio 下载文件归档 | Android Developers
Android Studio 简单介绍
Android Studio 是 Google 官方推出的 Android 应用开发集成环境(IDE),基于 JetBrains 的 IntelliJ IDEA 平台构建。它是开发 Android 原生应用和 Flutter 应用的推荐工具,提供了丰富的功能来帮助开发者高效编写、调试和测试应用程序, Android Studio 是一个功能齐全、插件丰富的现代化开发环境,不仅适用于传统 Android 开发,也是目前 Flutter 开发的首选 IDE。无论是新手学习,还是企业级项目开发,Android Studio 都提供了良好的开发支持与工具生态
2.2 安装 Flutter SDK
Flutter SDK 下载与安装步骤(Windows)
官方地址:Archive | Flutter
设置环境变量
在系统环境变量中新建变量
变量名:PUB_HOSTED_URL 变量值:https://pub.flutter-io.cn
变量名:FLUTTER_STORAGE_BASE_URL 变量值:https://storage.flutter-io.cn
在系统变量 PATH 中添加 Flutter bin目录
D:\flutter_windows_3.24.1-stable\flutter\bin
Android Studio 下载 SDK 工具和 Android SDK Comman-line Tools 并下载 Flutter 和 Dart 插件
执行命令
flutter doctor -v
首次执行 Flutter 命令会从网络中拉取 Dart SDK、flutter工具等,这个过程会比较漫长
可能一直卡在
C:\Users\zengjh1>D:\flutter_windows_3.22.1-stable\flutter\bin\flutter.bat doctor
Checking Dart SDK version…
Downloading Dart SDK from Flutter engine …只能耐心等待,或者关闭重来,下载完后会显示 flutter 结果
[√] Flutter (Channel stable, 3.24.1, on Microsoft Windows [版本 10.0.19044.5737], locale zh-CN) • Flutter version 3.24.1 on channel stable at D:\flutter_windows_3.24.1-stable\flutter • Upstream repository https://github.com/flutter/flutter.git • Framework revision 5874a72aa4 (11 months ago), 2024-08-20 16:46:00 -0500 • Engine revision c9b9d5780d • Dart version 3.5.1 • DevTools version 2.37.2 • Pub download mirror https://pub.flutter-io.cn • Flutter download mirror https://storage.flutter-io.cn [√] Windows Version (Installed version of Windows is version 10 or higher) [!] Android toolchain - develop for Android devices (Android SDK version 35.0.0) • Android SDK at D:\SDK • Platform android-35, build-tools 35.0.0 • ANDROID_SDK_ROOT = D:\SDK • Java binary at: C:\Program Files\Java\jdk-17\bin\java • Java version Java(TM) SE Runtime Environment (build 17+35-LTS-2724) X Android license status unknown. Run `flutter doctor --android-licenses` to accept the SDK licenses. See https://flutter.dev/to/windows-android-setup for more details. [√] Chrome - develop for the web • Chrome at C:\Users\zengjh1\AppData\Local\Google\Chrome\Application\chrome.exe [X] Visual Studio - develop Windows apps X Visual Studio not installed; this is necessary to develop Windows apps. Download at https://visualstudio.microsoft.com/downloads/. Please install the "Desktop development with C++" workload, including all of its default components [√] Android Studio (version 2024.3) • Android Studio at F:\Program Files\Android\Android Studio • Flutter plugin can be installed from: https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 21.0.6+-13355223-b631.42) [√] Connected device (3 available) • Windows (desktop) • windows • windows-x64 • Microsoft Windows [版本 10.0.19044.5737] • Chrome (web) • chrome • web-javascript • Google Chrome 117.0.5938.63 • Edge (web) • edge • web-javascript • Microsoft Edge 138.0.3351.65 [√] Network resources • All expected network resources are available. ! Doctor found issues in 2 categories.
会提示我们那些工具缺少了什么,我们用的是 AndroidStudio,所以只要保证 AndroidStudio 这一栏没问题就行
2.3 安装 Dart 插件和 Flutter 插件
在 Android Studio 中安装插件的方法
在 File -> Setting -> Plugins -> Marketplace 下搜索 Dart 和 Flutter 插件下载安装即可。
2.4 连接真实设备
- 设备开启开发者 USB 调试模式
- 设备连接与调试授权
3. 创建第一个 Flutter 项目
3.1 通过 Android Studio 创建 Flutter 项目
选择 Flutter 项目
配置 Flutter SDK path
项目配置
3.2 项目结构介绍
lib/
文件夹及主要 Dart 文件lib/
是 Dart 代码的主目录main.dart
是应用的启动文件,负责引导整个 UI 构建。项目结构建议按模块划分(如
pages/
、widgets/
等),便于组织和维护。
pubspec.yaml
文件含义pubspec.yaml
是 Flutter 和 Dart 项目的配置文件,用于声明项目的依赖、资源、版本信息、打包配置等内容。它类似于其他语言生态的配置文件,例如:
Node.js 的
package.json
Java 的
pom.xml
Python 的
requirements.txt
项目 功能描述 name
,version
定义项目元信息 dependencies
项目运行所需依赖 dev_dependencies
测试/开发所需依赖 flutter/assets
声明项目使用的图片、JSON、音频等资源 flutter/fonts
配置自定义字体 uses-material-design
是否使用 Material 风格设计
4. 编写第一个 Flutter 界面
4.1 了解 Widget 体系
StatelessWidget 和 StatefulWidget 区别
StatelessWidget(无状态组件)
StatelessWidget
是 不可变的 ,其构建内容在生命周期中不会发生变化。适用场景:
内容不需要更新,比如固定文本、图标、样式按钮等。
UI 仅依赖构造时传入的数据。
class HelloText extends StatelessWidget { final String name; const HelloText({super.key, required this.name}); Widget build(BuildContext context) { return Text('Hello, $name'); } }
StatefulWidget(有状态组件)
StatefulWidget
是 可变的 ,拥有自己的状态对象State
,当状态改变时会触发 UI 重新构建 (setState()
)。适用场景:
UI 需要根据用户交互或数据更新而改变
比如按钮点击计数、输入框内容、动画等。
class CounterWidget extends StatefulWidget { const CounterWidget({super.key}); State<CounterWidget> createState() => _CounterWidgetState(); } class _CounterWidgetState extends State<CounterWidget> { int _count = 0; void _increment() { setState(() { _count++; }); } Widget build(BuildContext context) { return Column( children: [ Text('Count: $_count'), ElevatedButton(onPressed: _increment, child: const Text('Increment')), ], ); } }
区别总结
特性 StatelessWidget StatefulWidget 状态是否可变 否(不可变) 是(可变) 是否持有状态对象 否 是(通过 State 类) UI 是否可动态更新 否 是(调用 setState()
)重建方式 构造函数参数变化时重建 setState()
调用后重建常见应用场景 静态文本、图标、按钮等 表单输入、计数器、动画等 Widget 树的概念
在 Flutter 中,一切都是 Widget,页面 UI 是由各种 Widget 通过嵌套组合而成的,这种嵌套结构被称为 Widget 树
什么是 Widget 树
Widget 树是指:一个页面上的所有元素(按钮、文字、图片、容器等)以”树“的结构从上到下排列组合而成。
每一个 Widget 都可能包含子 Widget,它们像”树枝”一样组成整个页面的布局和逻辑
MaterialApp └── Scaffold ├── AppBar └── Body └── Column ├── Text └── ElevatedButton
Widget 树的层级关系
父 Widget:包含其他 Widget(容器、布局等)
子 Widget:被包含在某个父 Widget 中
Flutter 会从上往下递归构建、渲染、更新整课 Widget 树
为什么理解 Widget 树很重要?
调试和布局排查:Widget 树帮助你理解某个组件在页面中的层级与位置;
性能优化:可以判断哪些 Widget 频繁重建,是否可以抽离为 Stateless;
构建思想转变:传统 UI 框架强调“修改视图”,Flutter 强调“重建 Widget 树”。
Widget 树的可视化工具
Flutter 提供了调试工具:
Flutter Inspector
(在 Android Studio、VSCode 中可用)可以查看实际 Widget 树结构,帮助开发者理解页面构造
总结
概念 说明 StatelessWidget
不可变组件,适合静态展示,构建后不会改变 StatefulWidget
可变组件,内部状态变化时可使用 setState()
触发重建Widget 树 所有 Widget 按嵌套结构组成的一棵树,构成 UI 的骨架
4.2 修改默认代码为“Hello World”
替换原先
main.dart
内容为import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp(); Widget build(BuildContext context) { return const MaterialApp( home: HelloWorldPage(), ); } } class HelloWorldPage extends StatelessWidget { const HelloWorldPage(); Widget build(BuildContext context) { return const Scaffold( body: Center( child: Text( 'Hello World', style: TextStyle(fontSize: 24), ), ), ); } }
5. Flutter 组件详解
5.1 基础组件
Text(文本显示)
用于在界面中显示一段文本
Text('Hello Flutter')
常用属性:
属性名 类型 说明 style
TextStyle
设置字体大小、颜色、粗细、行高等 textAlign
TextAlign
文本对齐方式(如 center
、left
)maxLines
int
显示的最大行数 overflow
TextOverflow
文本超出时的处理(如 ellipsis
)示例
Text( '欢迎学习 Flutter!', style: TextStyle( fontSize: 20, color: Colors.blue, fontWeight: FontWeight.bold ), textAlign: TextAlign.center, maxLines: 1, overflow: TextOverflow.ellipsis, )
Image(图片)
用于显示本地或网络图片
常用构造函数:
函数名 说明 Image.asset()
加载项目中的本地图片 Image.network()
加载网络图片 Image.file()
加载本地文件系统中的图片 Image.memory()
加载内存中的图片 示例
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { MyApp(); Widget build(BuildContext context) { return MaterialApp( home: HelloWorldPage(), ); } } class HelloWorldPage extends StatelessWidget { HelloWorldPage(); Widget build(BuildContext context) { return Scaffold( body: Center( child: Image.network( 'https://img.shetu66.com/zt/1661475606815_a10229ff.jpg', width: 200, height: 80, ), ), ); } }
Icon(图标)
用于显示 Material Design 风格的图标
基本用法
Icon(Icons.home)
常用属性
属性名 说明 Icons.xxx
图标名,Flutter 内置许多图标 size
图标大小 color
图标颜色 示例
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { MyApp(); Widget build(BuildContext context) { return MaterialApp( home: HelloWorldPage(), ); } } class HelloWorldPage extends StatelessWidget { HelloWorldPage(); Widget build(BuildContext context) { return Scaffold( body: Center( child: Icon( Icons.favorite, color: Colors.red, size: 32, ), ), ); } }
对比
组件 | 用途 | 典型构造方法 | 常用属性 |
---|---|---|---|
Text | 显示文字 | Text('xxx') |
style , textAlign |
Image | 显示图片 | Image.asset() , Image.network() |
width , height , fit |
Icon | 显示图标 | Icon(Icons.xxx) |
size , color |
5.2 布局组件
Container(容器)
Container
是一个组合型的组件(组合了尺寸、边距、填充、对齐、颜色、装饰、变换等功能)。它本身不渲染任何内容,但可以承载一个子 Widget,并通过属性来控制它的展示方式,它相当于
HTML 中的
<div>
+ CSS 中的 margin/padding/background/transform 组合体。常用属性
属性 类型 说明 child
Widget 子组件 width
/height
double 设置容器的宽度和高度 margin
EdgeInsets
外边距 padding
EdgeInsets
内边距(对子组件生效) color
Color 背景颜色(不能与 decoration.color
同时使用)alignment
Alignment
控制子组件在容器内的位置 decoration
BoxDecoration
背景装饰(如圆角、边框、背景图等) transform
Matrix4
容器的几何变换(如旋转、缩放、平移) 示例
设置宽高 + 背景色 + 子组件居中
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { MyApp(); Widget build(BuildContext context) { return MaterialApp( home: HelloWorldPage(), ); } } class HelloWorldPage extends StatelessWidget { HelloWorldPage(); Widget build(BuildContext context) { return Container( width: 200, height: 100, color: Colors.blue, alignment: Alignment.center, child: const Text('Hello Container', style: TextStyle(color: Colors.white)), ); } }
设置内边距和外边距
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { MyApp(); Widget build(BuildContext context) { return MaterialApp( home: HelloWorldPage(), ); } } class HelloWorldPage extends StatelessWidget { HelloWorldPage(); Widget build(BuildContext context) { return Container( margin: const EdgeInsets.all(16), padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), color: Colors.green, child: const Text('带边距的文本'), ); } }
使用装饰
decoration
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { MyApp(); Widget build(BuildContext context) { return MaterialApp( home: HelloWorldPage(), ); } } class HelloWorldPage extends StatelessWidget { HelloWorldPage(); Widget build(BuildContext context) { return Container( width: 150, height: 150, decoration: BoxDecoration( color: Colors.orange, borderRadius: BorderRadius.circular(16), border: Border.all(color: Colors.black, width: 2), ), child: const Center(child: Text('装饰效果')), ); } }
添加变换(旋转)
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { MyApp(); Widget build(BuildContext context) { return MaterialApp( home: HelloWorldPage(), ); } } class HelloWorldPage extends StatelessWidget { HelloWorldPage(); Widget build(BuildContext context) { return Container( width: 100, height: 100, color: Colors.purple, transform: Matrix4.rotationZ(0.2), alignment: Alignment.center, child: const Text('旋转'), ); } }
Padding(内边距)
Padding
是 Flutter 中用于给子组件添加 内边距(padding) 的布局组件。
它的作用是:在子组件的外部(但在边框内部)增加空白区域。语法结构
Padding( padding: EdgeInsets.all(8.0), // 设置内边距 child: Text('Hello Padding'), )
示例
四边统一内边距
Padding( padding: EdgeInsets.all(16), child: Text('我有 16 的内边距'), )
水平、垂直内边距不同
Padding( padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12), child: Text('左右 24,上下 12'), )
仅指定某个方向
Padding( padding: EdgeInsets.only(top: 20, left: 10), child: Text('仅上边距 20,左边距 10'), )
Padding
与Container
的区别特性 Padding
Container
设置内边距 专门用于设置内边距 (但只是组合属性的一部分) 设置颜色、大小 不支持 可以设置宽高、颜色、装饰等 推荐场景 专注间距控制 通用容器,做样式和布局控制更全面 Align(对齐)
Align
是 Flutter 中用于 对子组件进行位置控制 的组件。它会在自身范围内,将child
放置到指定的位置(例如居中、左上、右下等)基本语法
Align( alignment: Alignment.center, // 默认值 child: Text('居中显示') )
alignment 属性详解
常量 对应位置 Alignment.topLeft
左上角 Alignment.topCenter
上中 Alignment.topRight
右上角 Alignment.centerLeft
左中 Alignment.center
中间(默认) Alignment.centerRight
右中 Alignment.bottomLeft
左下角 Alignment.bottomCenter
下中 Alignment.bottomRight
右下角 本质上,
alignment
是一个二维坐标系:- ”
(-1, -1)
表示左上角,(1,1)
表示右下角,(0, 0)
表示正中间。“
示例
文字显示在右下角
Align( alignment: Alignment.bottomRight, child: Text('右下角文字'), )
放一张图片到左上角
Align( alignment: Alignment.topLeft, child: Image.asset('assets/images/avatar.png', width: 60), )
附加属性
widthFactor
和heightFactor
这些属性可以影响 Align 本身的大小
widthFactor
:子组件宽度 × 倍数,作为 Align 的宽度;heightFactor
:子组件高度 × 倍数,作为 Align 的高度;
Align( alignment: Alignment.center, widthFactor: 2, heightFactor: 2, child: Text('我是 2 倍大'), )
和其他对齐组件的区别
组件 功能描述 Align
精确控制子组件在父组件中的位置 Center
相当于 Align(alignment: Alignment.center)
Padding
设置内边距,但不能控制子组件的具体位置 Positioned
用于 Stack
中,绝对定位
- ”
Center(居中)
Center
是一个非常简单的布局组件,它的作用是:将子组件放在父容器的中心位置基本语法
Center( child: Text('居中显示'), )
它会自动让
Text
或其他子组件在父容器中 水平居中 + 垂直居中示例
居中显示文本
Center( child: Text( 'Hello Center', style: TextStyle(fontSize: 24), ), )
居中显示图片
Center( child: Image.asset('assets/images/logo.png', width: 100), )
结合
Container
使用Container( width: 300, height: 300, color: Colors.blue.shade100, child: Center( child: Text('我是居中的文字'), ), )
Center
和其他布局组件的区别组件 用途 特点 Center
子组件居中 最简单,等价于 Align.center
Align
子组件任意对齐 更灵活,需要手动指定 alignment
Padding
增加空白区域,但不控制对齐方式 Positioned
Stack
中做绝对定位需要配合 Stack
使用
Row(水平排列)
Row
是一个横向布局组件,用于 将多个组件水平排列在一行内基本语法
Row( children: [ Text('A'), Text('B'), Text('C'), ], )
这段代码会将
A B C
横向排在一行里。常用属性详情
属性名 类型 说明 children
List<Widget>
子组件列表 mainAxisAlignment
MainAxisAlignment
主轴(水平方向)对齐方式 crossAxisAlignment
CrossAxisAlignment
交叉轴(垂直方向)对齐方式 mainAxisSize
MainAxisSize
主轴尺寸:最大/最小(是否占满可用空间) textDirection
TextDirection
布局方向:从左到右(默认)还是从右到左 mainAxisAlignment
对齐选项(水平)属性 效果 MainAxisAlignment.start
左对齐(默认) MainAxisAlignment.center
水平居中 MainAxisAlignment.end
右对齐 MainAxisAlignment.spaceBetween
两端对齐,子项平均分布 MainAxisAlignment.spaceAround
子项周围空白相等 MainAxisAlignment.spaceEvenly
子项之间空白完全相等 示例
Row( mainAxisAlignment: MainAxisAlignment.center, children: const [ Icon(Icons.star, color: Colors.red), Icon(Icons.star_border, color: Colors.red), Icon(Icons.star_half, color: Colors.red), ], )
crossAxisAlignment
对齐选项(垂直)属性 效果 CrossAxisAlignment.start
顶部对齐 CrossAxisAlignment.center
垂直居中(默认) CrossAxisAlignment.end
底部对齐 CrossAxisAlignment.stretch
拉伸子项填满垂直空间 baseline
(需设置 textBaseline)按文本基线对齐
Column(垂直排列)
Column
是一个 竖直方向布局组件 ,可以让多个子组件 从上到下一次排列基本语法
Column( children: [ Text('第一行'), Text('第二行'), Text('第三行'), ], )
常用属性解释
属性名 类型 说明 children
List<Widget>
子组件列表 mainAxisAlignment
MainAxisAlignment
主轴(竖直方向)对齐方式 crossAxisAlignment
CrossAxisAlignment
交叉轴(水平方向)对齐方式 mainAxisSize
MainAxisSize
主轴大小控制(是否占满可用垂直空间) 主轴对齐(mainAxisAlignment)
控制子组件在竖直方向上的排列方式:
属性值 效果 MainAxisAlignment.start
从顶部开始(默认) MainAxisAlignment.center
垂直居中 MainAxisAlignment.end
底部对齐 MainAxisAlignment.spaceBetween
上下贴边,中间平均分布 MainAxisAlignment.spaceAround
每个子组件周围间距相等 MainAxisAlignment.spaceEvenly
所有子组件间距完全相等 交叉轴对齐(crossAxisAlignment)
控制子组件在水平方向上的对齐方式
属性值 效果 CrossAxisAlignment.start
左对齐(默认) CrossAxisAlignment.center
水平居中 CrossAxisAlignment.end
右对齐 CrossAxisAlignment.stretch
拉伸子组件到最大宽度
示例
简单垂直排布
Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: const [ Text('标题'), SizedBox(height: 10), Text('副标题'), SizedBox(height: 10), Icon(Icons.star, size: 32), ], )
加背景 + 居中演示(配合 Container)
Container( width: double.infinity, height: 300, color: Colors.blue.shade50, child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.center, children: const [ Text('上'), Text('中'), Text('下'), ], ), )
Stack(层叠布局)
Stack
是一个 堆叠布局组件 允许多个子组件 按照 z 轴 (前后)方向叠加在一起基本语法
Stack( children: [ Container(width: 200, height: 200, color: Colors.blue), Positioned( top: 20, left: 20, child: Icon(Icons.star, size: 50, color: Colors.white), ), ], )
常用属性解释
属性名 类型 说明 children
List<Widget>
所有子组件,越靠后越在上层 alignment
Alignment
控制非 Positioned 子组件的位置 fit
StackFit
控制子组件尺寸如何适应 Stack clipBehavior
Clip
是否裁剪超出部分(默认 Clip.hardEdge
)Stack
vsPositioned
Stack
用来定义多个叠加的层Positioned
用来对某个子组件进行绝定位
和基本语法示例对比
Stack( children: [ Container(color: Colors.yellow, width: 200, height: 200), Positioned( bottom: 10, right: 10, child: Text('右下角'), ), ], )
alignment:对非 Positioned 的子组件对齐
Stack( alignment: Alignment.center, children: [ Container(width: 100, height: 100, color: Colors.red), Text('居中'), // 自动居中 ], )
5.3 按钮和交互组neiElevatedButton / TextButton / OutlinedButton(各种按钮)
ElevatedButton / TextButton / OutlinedButton(各种按钮)
按钮类型 外观描述 适用场景 ElevatedButton
有阴影、背景填充、立体感强 用于强调操作,如“提交” TextButton
无边框、无背景,仅文本 用于辅助操作、二级选项 OutlinedButton
有边框但无背景 用于不那么主要的操作按钮 ElevatedButton
立体按钮Container( child: Column( children: [ ElevatedButton( onPressed: () { print('点击了 ElevatedButton'); }, child: Text('确定'), ) ], ), color: Colors.white, )
常用于强调主要操作,例如 “登录”、“提交”。
TextButton
(纯文本按钮)TextButton( onPressed: () { print('点击了 TextButton'); }, child: Text('取消'), )
用于不那么显眼的按钮,比如“忘记密码”、“查看更多”。
OutlinedButton
(带边框按钮)OutlinedButton( onPressed: () { print('点击了 OutlinedButton'); }, child: Text('边框按钮'), )
用于中性操作,比如“跳过”、“稍后再说”。
自定义按钮样式
三种按钮都支持使用
style
参数来自定义外观,使用ButtonStyle
类ElevatedButton( onPressed: () {}, style: ElevatedButton.styleFrom( primary: Colors.blue, // 背景色 onPrimary: Colors.white, // 文字颜色 padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: Text('自定义样式'), )
使用场景建议
场景 推荐按钮类型 提交、主操作 ElevatedButton
取消、跳过、轻操作 TextButton
次要但需强调(边界操作) OutlinedButton
图标 + 文本按钮 *.icon()
系列
GestureDetector(手势识别)
GestureDetector
是一个 手势识别器 可以监听用户在屏幕上的各种操作(手势)如点击(Tap)
双机(Double Tap)
长按(Long Press)
拖动(Drag)
缩放(Scale)
基本语法
GestureDetector( onTap: () { print('点击了组件'); }, child: Container( color: Colors.blue, padding: EdgeInsets.all(20), child: Text('点我'), ), )
常用事件一览
属性名 类型 说明 onTap
void Function()
单击 onDoubleTap
void Function()
双击 onLongPress
void Function()
长按 onPanUpdate
Function(DragUpdateDetails)
拖动时触发(全向) onPanStart
/onPanEnd
- 拖动开始 / 结束 onScaleUpdate
Function(ScaleUpdateDetails)
双指缩放
示例
点击、长按、双击事件
GestureDetector( onTap: () => print('点击'), onDoubleTap: () => print('双击'), onLongPress: () => print('长按'), child: Container( padding: EdgeInsets.all(20), color: Colors.lightGreen, child: Text('点我试试'), ), )
拖动(onPanUpdate)
GestureDetector( onPanUpdate: (details) { print('dx: ${details.delta.dx}, dy: ${details.delta.dy}'); }, child: Container( width: 200, height: 200, color: Colors.orange, child: Center(child: Text('拖动我')), ), )
缩放(onScaleUpdate)
GestureDetector( onScaleUpdate: (details) { print('缩放比例:${details.scale}'); }, child: Image.asset('assets/images/logo.png'), )
总结
功能 | 是否支持 | 示例属性 |
---|---|---|
点击 | 支持 | onTap |
双击 | 支持 | onDoubleTap |
长按 | 支持 | onLongPress |
拖动 | 支持 | onPanUpdate |
缩放 | 支持 | onScaleUpdate |
支持嵌套其他组件 | 支持 | child |
无视觉效果(非按钮) | 支持 | 需要自定义样式 |
InkWell(水波纹效果点击)
InkWell
是一个 带水波纹(涟漪)点击效果的手势识别组件。 相比GestureDetector
它有更好的 Material 设计风格的视觉效果它属于 Material 组件体系的一部分,使用时需要有
Material
组件作为“水波纹的绘制容器”基本用法
InkWell( onTap: () { print('点击了 InkWell'); }, child: Padding( padding: EdgeInsets.all(16), child: Text('点我'), ), )
点击时会看到水波纹从点击点扩散开来
常用属性
属性名 类型 说明 onTap
void Function()?
点击事件 onDoubleTap
void Function()?
双击事件 onLongPress
void Function()?
长按事件 borderRadius
BorderRadius
设置水波纹圆角 splashColor
Color
设置水波纹颜色 highlightColor
Color
按下时的背景色 child
Widget
显示内容 配合
Material
使用 (必须)Material( color: Colors.blue[50], borderRadius: BorderRadius.circular(12), child: InkWell( onTap: () { print('点到了卡片'); }, borderRadius: BorderRadius.circular(12), splashColor: Colors.redAccent.withOpacity(0.2), child: Padding( padding: EdgeInsets.all(20), child: Text('有点击水波纹的卡片'), ), ), )
和
GestureDetectro
区别对比对比点 GestureDetector
InkWell
是否有视觉反馈 无水波纹 有水波纹 是否依赖 Material
不依赖 必须依赖 Material 父组件 支持的手势种类 拖动、缩放、滑动等更丰富 主要用于点击相关 使用场景 自定义复杂交互 通常用于按钮、卡片、列表点击反馈等
5.4 输入框和表单
TextField(文本输入)
TextField
是最常用的文本输入组件,用于实现表单的输入、搜索框、聊天框等各种输入功能基本用法
TextField( decoration: InputDecoration( labelText: '用户名', hintText: '请输入用户名', border: OutlineInputBorder(), ), )
效果:一个带标签、提示文字、边框的输入框
常用属性详情
属性名 类型 说明 controller
TextEditingController
控制和监听输入框内容 decoration
InputDecoration
装饰输入框(如提示、图标、边框等) obscureText
bool
是否隐藏输入内容(用于密码) keyboardType
TextInputType
输入类型(文本、数字、邮箱等) maxLines
int
输入框最大行数 onChanged
Function(String)
文本改变时回调 onSubmitted
Function(String)
用户按下“完成/提交”时的回调 enabled
bool
是否可编辑 readOnly
bool
是否只读
示例
带控制器示例(获取输入内容)
class TextFieldExample extends StatelessWidget { final TextEditingController _controller = TextEditingController(); Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('TextField 示例')), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ TextField( controller: _controller, decoration: InputDecoration(labelText: '输入内容'), ), SizedBox(height: 20), ElevatedButton( onPressed: () { print("你输入了: ${_controller.text}"); }, child: Text('提交')) ], ), ), ); } }
密码框(隐藏输入)
TextField( obscureText: true, decoration: InputDecoration( labelText: '密码', border: OutlineInputBorder(), ), )
不同输入类型
输入类型 示例设置 文本(默认) keyboardType: TextInputType.text
数字 keyboardType: TextInputType.number
电话 keyboardType: TextInputType.phone
邮箱 keyboardType: TextInputType.emailAddress
多行输入
TextField( maxLines: 5, decoration: InputDecoration(labelText: '多行备注'), )
自定义装饰 InputDecoration 示例
TextField( decoration: InputDecoration( prefixIcon: Icon(Icons.person), suffixIcon: Icon(Icons.clear), labelText: '用户名', hintText: '请输入用户名', border: OutlineInputBorder(), ), )
Checkbox(多选框)
Checkbox
是一个可以勾选/取消的组件,只有两个状态(true
/false
) 可以搭配文字或图标一起使用。基本用法
bool _isChecked = false; Checkbox( value: _isChecked, onChanged: (bool? value) { setState(() { _isChecked = value!; }); }, )
必须在
StatefulWidget
中使用,因为复选框的值需要动态更新。示例
class CheckBoxDemo extends StatefulWidget { _CheckBoxDemoState createState() => _CheckBoxDemoState(); } class _CheckBoxDemoState extends State<CheckBoxDemo> { bool _isSelected = false; Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("Checkbox 示例")), body: Center( child: Row( mainAxisSize: MainAxisSize.min, children: [ Checkbox( value: _isSelected, onChanged: (bool? value) { setState(() { _isSelected = value!; }); }, ), Text(_isSelected ? "已选中" : "未选中"), ], ), ), ); } }
常用属性
属性名 类型 说明 value
bool
当前是否勾选 onChanged
(bool?) → void
勾选状态变化时的回调函数 activeColor
Color
选中时的颜色 checkColor
Color
号颜色 tristate
bool
是否支持三种状态(true/false/null) 搭配
CheckboxListTitle
(复选框 + 标题 + 子标题)CheckboxListTile( title: Text("我同意协议"), subtitle: Text("点击确认后继续"), value: _isChecked, onChanged: (value) { setState(() { _isChecked = value!; }); }, secondary: Icon(Icons.policy), controlAffinity: ListTileControlAffinity.leading, )
总结
你想实现的功能 使用方式或属性 基本复选框 Checkbox
复选框 + 文字 Row + Text
或CheckboxListTile
支持不确定(null)状态 tristate: true
更好看的样式和布局 用 CheckboxListTile
Radio(单选框)
Radio<T>
是 Flutter 提供的泛型组件,用于在多个选项中选择一个,必须搭配groupValue
一起使用。最基本的用法示例
Radio<int>( value: 1, groupValue: _selectedValue, onChanged: (int? value) { setState(() { _selectedValue = value!; }); }, )
value
:表示当前这个单选按钮的值groupValue
:表示当前“选中的值”onChanged
:当点击时调用,传入的就是value
选择性别示例:
class RadioDemo extends StatefulWidget { _RadioDemoState createState() => _RadioDemoState(); } class _RadioDemoState extends State<RadioDemo> { String _gender = "男"; Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("Radio 示例")), body: Column( children: [ ListTile( title: Text("男"), leading: Radio<String>( value: "男", groupValue: _gender, onChanged: (value) { setState(() { _gender = value!; }); }, ), ), ListTile( title: Text("女"), leading: Radio<String>( value: "女", groupValue: _gender, onChanged: (value) { setState(() { _gender = value!; }); }, ), ), SizedBox(height: 20), Text("你选择的是:$_gender"), ], ), ); } }
常用属性一览
属性名 类型 说明 value
T
当前这个选项的值 groupValue
T
当前组中被选中的值 onChanged
Function(T?)
点击时回调 activeColor
Color
选中状态颜色 toggleable
bool
是否支持再次点击取消(Flutter 3.7+) Switch(开关)
Switch
是 Flutter 提供的滑动切换组件,只有两个状态:true
(开启)和false
(关闭)最基本的用法
bool _isOn = false; Switch( value: _isOn, onChanged: (bool value) { setState(() { _isOn = value; }); }, )
必须在
StatefulWidget
中使用,因为开关状态需要实时更新。示例:
控制某功能开关
class SwitchDemo extends StatefulWidget { _SwitchDemoState createState() => _SwitchDemoState(); } class _SwitchDemoState extends State<SwitchDemo> { bool _isDarkMode = false; Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("Switch 示例")), body: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Switch( value: _isDarkMode, onChanged: (bool value) { setState(() { _isDarkMode = value; }); }, ), Text(_isDarkMode ? '暗黑模式已开启' : '暗黑模式已关闭'), ], ), ); } }
常用属性
属性名 类型 说明 value
bool
当前开关状态 onChanged
(bool) → void
状态变化回调函数 activeColor
Color
开启时的主色(圆点颜色) activeTrackColor
Color
开启时轨道颜色 inactiveThumbColor
Color
关闭时圆点颜色 inactiveTrackColor
Color
关闭时轨道颜色 materialTapTargetSize
MaterialTapTargetSize
调整点击区域大小 Form 与 FormField(表单管理)
在 Flutter 中,
Form
和FormField
是用于统一管理多个输入组件的表单系统,可以方便地进行表单验证、提交等操作,常用于登录、注册、反馈等界面。什么是
Form
和FormField
组件 作用说明 Form
表单容器,用于管理一组输入项(字段) FormField
表单字段的基类(如 TextFormField) TextFormField
是最常用的FormField
实现,是带表单验证功能的输入框Form
的基本结构final _formKey = GlobalKey<FormState>(); Form( key: _formKey, child: Column( children: [ TextFormField( decoration: InputDecoration(labelText: '用户名'), validator: (value) { if (value == null || value.isEmpty) { return '请输入用户名'; } return null; }, ), ElevatedButton( onPressed: () { if (_formKey.currentState!.validate()) { // 所有字段验证通过 print('验证成功,提交数据'); } }, child: Text('提交'), ), ], ), )
关键知识点说明
项目 说明 FormState
表单状态对象,管理字段验证、保存等操作 GlobalKey<FormState>
唯一标识表单,获取 FormState
对象validate()
执行所有字段的 validator
方法,返回是否通过验证save()
触发每个字段的 onSaved
回调(如果设置)reset()
重置所有字段内容和状态 完整示例
class FormExample extends StatefulWidget { _FormExampleState createState() => _FormExampleState(); } class _FormExampleState extends State<FormExample> { final _formKey = GlobalKey<FormState>(); String _username = ''; String _password = ''; Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Form 表单示例')), body: Padding( padding: EdgeInsets.all(16), child: Form( key: _formKey, child: Column( children: [ TextFormField( decoration: InputDecoration(labelText: '用户名'), validator: (value) { if (value == null || value.isEmpty) { return '请输入用户名'; } return null; }, onSaved: (value) { _username = value!; }, ), TextFormField( decoration: InputDecoration(labelText: '密码'), obscureText: true, validator: (value) { if (value == null || value.length < 6) { return '密码不能少于6位'; } return null; }, onSaved: (value) { _password = value!; }, ), SizedBox(height: 20), ElevatedButton( onPressed: () { if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); print('用户名: $_username'); print('密码: $_password'); } }, child: Text('提交'), ), ], ), ), ), ); } }
TextField
VSTextFormField
区别项 TextField
TextFormField
表单验证支持 无验证方法 支持 validator/onSaved 等 与 Form 配合使用 需要单独管理状态 可统一使用 Form 管理 推荐使用场景 简单输入框 表单场景(如登录、注册等) 一些常用方法(FormState)
方法名 说明 validate()
所有字段验证,返回布尔值 save()
调用每个字段的 onSaved()
reset()
重置整个表单
5.5 滚动视图
ListView(列表)
ListView
是一个 可滚动的线性列表视图组件 可以直接或水平显示一系列子组件最基本的用法
ListView( children: [ ListTile(title: Text('第1项')), ListTile(title: Text('第2项')), ListTile(title: Text('第3项')), ], )
默认是垂直方向的,超出屏幕会自动滚动。
常见构造方式
ListView
+children
: 静态少量内容ListView.builder
: 动态列表(推荐)ListView.separated
: 带分隔线ListView.custom
: 高级自定义构造(极少用)
常用属性
属性名 类型 说明 itemCount
int
列表项数量(用于 builder) itemBuilder
IndexedWidgetBuilder
构建每项内容的方法 scrollDirection
Axis
滚动方向( Axis.vertical
/horizontal
)reverse
bool
是否反转列表显示顺序 shrinkWrap
bool
是否根据内容自动收缩高度 physics
ScrollPhysics
滚动行为(如禁止、弹性等) padding
EdgeInsets
设置内边距 示例
class ListViewDemo extends StatelessWidget { final List<String> items = List.generate(20, (index) => '项目 $index'); Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('ListView 示例')), body: ListView.builder( itemCount: items.length, itemBuilder: (context, index) { return ListTile( leading: Icon(Icons.start), title: Text(items[index]), onTap: () { print('你点击了: ${items[index]}'); }, ); })); } }
GridView(网格)
GridView
(网格布局),它是用来显示多列(多行多列)的组件,常用于图片展示、商品列表、图标宫格菜单等场景。GridView
是一个支持滚动的二维网格布局组件,和ListView
类似,但可以在横向上自动分布多个元素。常用构造方法
GridView.count
(常规固定列数网格)GridView.count( crossAxisCount: 3, children: List.generate(9, index { return Container( alignment: Alignment.center, color: Colors.blue[100 * ((index % 8) + 1)], child: Text('项 $index') ); }); );
GridView.builder
(推荐用于大数据列表)GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, // 每行 2 个 crossAxisSpacing: 10, // 横向间距 mainAxisSpacing: 10, // 纵向间距 childAspectRatio: 1.5, // 宽高比(默认是 1) ), itemCount: 20, itemBuilder: (context, index) { return Container( color: Colors.teal[100 * ((index % 8) + 1)], alignment: Alignment.center, child: Text('Grid $index'), ); }, )
GridView.extent
(指定最大宽度自动适配列数)GridView.extent( maxCrossAxisExtent: 100, // 每个项最大宽度,系统自动决定多少列 children: List.generate(20, (index) { return Container( alignment: Alignment.center, color: Colors.orange[100 * ((index % 8) + 1)], child: Text('Item $index'), ); }), )
常用属性说明
属性名 类型 说明 crossAxisCount
int
每行显示的列数 mainAxisSpacing
double
每行之间的间距(垂直方向) crossAxisSpacing
double
每列之间的间距(水平方向) childAspectRatio
double
宽高比(宽/高) shrinkWrap
bool
是否根据内容高度自适应(适用于嵌套) physics
ScrollPhysics
滚动行为(常用于嵌套时禁用滚动) 示例
import 'package:flutter/material.dart'; class GridViewExample extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('GridView 示例')), body: GridView.builder( padding: EdgeInsets.all(10), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, // 3列 crossAxisSpacing: 10, mainAxisSpacing: 10, childAspectRatio: 1.0, // 宽高比 1:1 ), itemCount: 12, itemBuilder: (context, index) { return Container( color: Colors.blue[100 * ((index % 8) + 1)], alignment: Alignment.center, child: Text('第 $index 项'), ); }, ), ); } }
SingleChildScrollView(单子节点滚动)
SingleChildScrollView
允许一个子组件在主轴滚动(通常是垂直) 适用于控件数量不定时避免溢出(overflow)错误。基本用法
SingleChildScrollView( child: Column( children: [ Text('A'), Text('B'), Text('C'), // 很多内容... ], ), )
SingleChildScrollView
的child
只能是 一个 Widget,通常搭配Column
使用。典型使用场景
登录页 / 注册页(键盘弹出时防止布局溢出)
表单页面(需要整体滚动)
多控件组合的页面(不是列表)
重要属性说明
属性名 类型 说明 scrollDirection
Axis
滚动方向,默认是 Axis.vertical
padding
EdgeInsets
内边距 reverse
bool
是否反向滚动 physics
ScrollPhysics
滚动行为(如弹性、不可滚动) controller
ScrollController
控制滚动、监听滚动位置等 示例
import 'package:flutter/material.dart'; class ScrollDemo extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('SingleChildScrollView 示例')), body: SingleChildScrollView( padding: EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: List.generate(20, (index) { return Padding(padding: EdgeInsets.symmetric(vertical: 8), child: Text('第 $index 行文本内容')); }), ), ), ); } }
与
ListView
区别对比对比项 SingleChildScrollView
ListView
用法场景 多个固定控件、表单页面 长列表、动态项 性能优化 没有懒加载,所有内容一次性渲染 支持懒加载 子组件结构 一个 Widget(如 Column
)包多个控件多个 Widget 构建 嵌套使用 更适合嵌套在页面中或布局中 嵌套需注意高度限制和滚动冲突
5.6 导航和路由
Navigator 介绍
Navigator
是用于管理页面(Route)跳转和堆栈操作的组件,类似网页的前进、后退、跳转操作。什么是
Navigator
?Navigator
是一个页面堆栈管理器,你可以:push:打开新页面(入栈)
pop:返回上一个页面(出栈)
replace:替换当前页面
清空所有页面再跳转:跳转并清空历史
Navigator 通常配合
MaterialPageRoute
或named route
使用。最基础的页面跳转方式
跳转到新页面(push)
Navigator.push( context, MaterialPageRoute(builder: (context) => SecondPage()), );
返回上一级页面(pop)
Navigator.pop(context);
带返回值的页面跳转
A → B,B返回数据给A:
在 A 页面:
void _goToSecondPage() async { final result = await Navigator.push( context, MaterialPageRoute(builder: (context) => SecondPage()), ); print("从第二页返回的数据: $result"); }
在 B 页面:
ElevatedButton( onPressed: () { Navigator.pop(context, "这是返回值"); }, child: Text("返回并携带数据"), )
使用命名路由(推荐方式)
定义路由表
MaterialApp( initialRoute: '/', routes: { '/': (context) => HomePage(), '/second': (context) => SecondPage(), }, )
跳转方式
Navigator.pushNamed(context, '/second');
返回方式
Navigator.pop(context);
常见跳转方式对比
跳转方式 用法 适合场景 push()
直接传入 Widget 简单项目 pushNamed()
使用路由名称跳转 大型项目,统一管理路由 pushReplacement()
替换当前页面(无返回) 登录成功替换登录页等 pushAndRemoveUntil()
清空历史再跳转 登录后清空所有导航栈 小结
功能 推荐方式 普通页面跳转 Navigator.push()
命名路由跳转 Navigator.pushNamed()
页面返回携带数据 Navigator.pop(context, result)
替换页面,不保留返回 Navigator.pushReplacement()
清空页面栈并跳转 Navigator.pushAndRemoveUntil()
push 和 pop
push
和pop
是 Flutter 中Navigator
导航系统的两个最核心方法,分别用于打开新页面和返回上一个页面,就像“网页的前进和后退”。Navigator.push()
作用:** 打开(压栈)一个新页面**
Navigator.push( context, MaterialPageRoute(builder: (context) => SecondPage()), );
context
:当前页面的上下文MaterialPageRoute
:常用的页面过渡动画(安卓风格)SecondPage()
:你要跳转的新页面 Widget
示例
ElevatedButton( onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (context) => SecondPage()), ); }, child: Text("去第二页"), )
Navigator.pop()
作用:返回(出栈)上一个页面
Navigator.pop(context);
可选地返回一个值:
Navigator.pop(context, "返回的数据");
push
+pop
结合使用(带返回值)第一个页面
void _goToSecondPage() async { final result = await Navigator.push( context, MaterialPageRoute(builder: (context) => SecondPage()), ); print("从第二页返回的数据是:$result"); }
第二个页面
ElevatedButton( onPressed: () { Navigator.pop(context, "你好,这是返回值"); }, child: Text("返回并传数据"), )
Navigator 的“堆栈”原理图示
初始: [ HomePage ] push(SecondPage) [ HomePage, SecondPage ] push(ThirdPage) [ HomePage, SecondPage, ThirdPage ] pop() [ HomePage, SecondPage ]
push / pop 常见变体
方法名 功能说明 push()
压入新页面 pop()
弹出当前页面 pushReplacement()
替换当前页面 popUntil()
返回到满足条件的页面 pushAndRemoveUntil()
清空页面栈并跳转 总结
功能 方法 打开新页面 Navigator.push()
返回上一页 Navigator.pop()
替换当前页面 Navigator.pushReplacement()
返回并带数据 Navigator.pop(context, value)
多页面返回(条件) Navigator.popUntil()
5.7 其他常用组件
AppBar(应用栏)
AppBar
是 Scaffold(脚手架页面)的顶部栏,常用于显示:页面标题(title)、返回按钮(自动生成)、操作按钮(Icon)、搜索框、TabBar、菜单等它是 Flutter 应用中几乎每个页面都会使用的标准导航栏。
基本语法
Scaffold( appBar: AppBar( title: Text('我是标题'), ), body: Center(child: Text('内容')), )
常用属性说明
属性名 类型 作用说明 title
Widget
应用栏的标题,通常是 Text
leading
Widget
左侧图标(默认是返回箭头) actions
List<Widget>
右侧图标按钮列表 backgroundColor
Color
背景颜色 centerTitle
bool
是否居中标题(iOS 默认为 true) elevation
double
阴影高度(默认 4) bottom
PreferredSizeWidget
下方扩展区域,如 TabBar
示例
import 'package:flutter/material.dart'; class AppBarExample extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('AppBar 示例'), leading: Icon(Icons.menu), actions: [ IconButton( icon: Icon(Icons.search), onPressed: () { print('搜索按钮点击'); }, ), IconButton( icon: Icon(Icons.more_vert), onPressed: () { print('更多菜单'); }, ), ], ), body: Center( child: Text('页面内容区域'), ), ); } }
Scaffold(脚手架,基础页面布局)
Scaffold
是 Flutter 提供的 页面结构容器,提供了一个基本布局框架,包含:AppBar(顶部应用栏)、Body(主要内容区)、Drawer(侧边栏)、BottomNavigationBar(底部导航)、FloatingActionButton(悬浮按钮)、SnackBar(轻提示)等。它就像“页面的骨架”,你把各种 UI 部件放进去就可以构成完整的页面。
基本使用方式
Scaffold( appBar: AppBar(title: Text("首页")), body: Center(child: Text("Hello World")), )
Scaffold 的常用属性详解
属性名 类型 作用说明 appBar
AppBar
页面顶部导航栏 body
Widget
页面主要内容区域 floatingActionButton
FloatingActionButton
页面悬浮按钮 drawer
Drawer
左侧滑出菜单 bottomNavigationBar
BottomNavigationBar
页面底部导航栏 backgroundColor
Color
页面背景色 persistentFooterButtons
List<Widget>
固定在底部的按钮组 bottomSheet
Widget
页面底部悬浮层 示例
import 'package:flutter/material.dart'; class ScaffoldExample extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Scaffold 示例')), body: Center(child: Text('我是页面内容')), floatingActionButton: FloatingActionButton( onPressed: () { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text("你点击了按钮")), ); }, child: Icon(Icons.add), ), drawer: Drawer( child: ListView( children: [ DrawerHeader( decoration: BoxDecoration(color: Colors.blue), child: Text("菜单头部", style: TextStyle(color: Colors.white))), ListTile(title: Text("选项1")), ListTile(title: Text("选项2")) ], ), ), bottomNavigationBar: BottomAppBar( child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ IconButton(onPressed: (){}, icon: Icon(Icons.home)), IconButton(onPressed: (){}, icon: Icon(Icons.person)) ], ), ), ); } }
常见组合搭配
页面需求 Scaffold 结构用法 普通页面(顶部+内容) appBar + body
带悬浮操作按钮 floatingActionButton
左侧菜单导航 drawer
底部固定菜单栏 bottomNavigationBar
orBottomAppBar
显示提示 ScaffoldMessenger.of(context).showSnackBar(...)
Drawer(抽屉导航)
Drawer
是 Scaffold 提供的一个侧边导航菜单,通常从左边滑出,用于展示导航选项、用户信息等。基本结构
Drawer( child: ListView( padding: EdgeInsets.zero, children: [ DrawerHeader( decoration: BoxDecoration(color: Colors.blue), child: Text('用户信息'), ), ListTile( leading: Icon(Icons.home), title: Text('首页'), onTap: () { // 点击事件 }, ), ListTile( leading: Icon(Icons.settings), title: Text('设置'), onTap: () { // 点击事件 }, ), ], ), )
Drawer 常用组件说明
组件 作用 DrawerHeader
抽屉顶部区域,一般用于展示用户头像、昵称 ListTile
列表项,一般用于菜单选项 ListView
内容可滚动 打开与关闭 Drawer
自动打开
用户手动左滑
点左上角菜单按钮(如果 AppBar 中设置了 automaticallyImplyLeading: true)
手动打开
Scaffold.of(context).openDrawer(); // 仅限于在子 Widget 中使用 Builder 包裹
手动关闭
Navigator.pop(context)
示例
class DrawerExample extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Drawer 示例')), drawer: Drawer( child: ListView( padding: EdgeInsets.zero, children: [ const UserAccountsDrawerHeader( accountName: Text('张三'), accountEmail: Text("zhangsan@example.com"), currentAccountPicture: CircleAvatar( backgroundImage: AssetImage('assets/images/ic_launcher.png'), ), ), ListTile( leading: const Icon(Icons.home), title: const Text('首页'), onTap: () { Navigator.pop(context); }, ), ListTile( leading: const Icon(Icons.settings), title: const Text('设置'), onTap: () { Navigator.pop(context); }, ), ], ), ), body: const Center(child: Text('主页面内容')) ); } }
小结
你要实现的功能 推荐做法 左侧菜单导航 使用 Scaffold.drawer
右侧快捷操作菜单 使用 Scaffold.endDrawer
展示用户头像信息 使用 UserAccountsDrawerHeader
菜单点击关闭并跳转 先 Navigator.pop()
再导航页面
BottomNavigationBar(底部导航栏)
BottomNavigationBar
是 Flutter 提供的一个底部导航栏组件,配合Scaffold
使用,支持多个标签切换视图页面。它可以 : 显示多个 tab 标签(一般 3 ~ 5 个);高亮当前选中项;点击切换页面(配合
IndexedStack
)基本用法
Scaffold( bottomNavigationBar: BottomNavigationBar( currentIndex: 0, // 当前选中索引 onTap: (index) { // 切换页面逻辑 }, items: [ BottomNavigationBarItem( icon: Icon(Icons.home), label: '首页', ), BottomNavigationBarItem( icon: Icon(Icons.person), label: '我的', ), ], ), )
示例
import 'package:flutter/material.dart'; class BottomNavExample extends StatefulWidget { _BottomNavExampleState createState() => _BottomNavExampleState(); } class _BottomNavExampleState extends State<BottomNavExample> { int _currentIndex = 0; final List<Widget> _pages = [ Center(child: Text('首页内容')), Center(child: Text('分类内容')), Center(child: Text('我的内容')) ]; Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("底部导航示例")), body: IndexedStack ( index: _currentIndex, children: _pages, ), bottomNavigationBar: BottomNavigationBar ( currentIndex: _currentIndex, onTap: (index) { setState(() { _currentIndex = index; }); }, items: [ BottomNavigationBarItem(icon: Icon(Icons.home), label: "首页"), BottomNavigationBarItem(icon: Icon(Icons.category), label: "分类"), BottomNavigationBarItem(icon: Icon(Icons.person), label: "我的"), ], ), ); } }
属性说明
属性名 类型 说明 items
List 菜单项(最少2项) currentIndex
int 当前选中项的索引 onTap
Function(int) 点击导航项回调 type
BottomNavigationBarType 显示样式: fixed
(默认)或shifting
(动效)selectedItemColor
Color 选中项颜色 unselectedItemColor
Color 未选中项颜色 backgroundColor
Color 背景色
6. 状态管理基础
6.1 什么是状态?
简单来说,状态就是某个变量的值 当这个值发生变化时,对应的 UI会自动刷新 展示新的内容,
比如:
一个计数器的数字是状态 (
count = 3
)一个按钮是否选中是状态(
isSelected = true
)一个页面当前是“加载中”还是“已完成”是状态(
loading = true / false
)
示例
int count = 0; // 这就是一个状态
ElevatedButton(
onPressed: () {
setState(() {
count++;
});
},
child: Text('点击了 $count 次'),
)
Flutter 中状态是怎么驱动 UI 的?
Flutter 的 Widget 是声明时UI,它不是手动改动控件,而是重新构建:
// 当状态改变时 setState((){ count++; // 修改状态 }); // Flutter 自动重新调用 build() -> 根据新状态更新 UI
这就是 Flutter 的核心机制: 状态驱动UI
状态在哪些 Widget 中存在?
Widget 类型 状态管理方式 StatelessWidget(无状态) 固定不变的 UI,只能显示数据 StatefulWidget(有状态) 可变 UI,状态变化会自动刷新 常见状态的例子
场景 状态变量 计数器 int counter
登录表单 String username
,password
切换主题 bool isDarkMode
是否选中某项 bool isChecked
当前页面索引 int currentIndex
7. 资源管理
图片资源的使用
在 Flutter 中使用图片资源是构建 UI 的基本技能之一,分为以下几类资源使用方式:
Flutter 中的图片来源类型
图片来源 示例 使用方式 本地 assets 项目中的 assets/images/
Image.asset(...)
网络图片 网络链接 Image.network(...)
内存 / 字节流 Uint8List 数据 Image.memory(...)
文件系统图片 本地文件路径 Image.file(...)
使用本地图片(
assets
)步骤一:创建
assets
目录在项目根目录下创建文件夹:
/assets/images/
放入图片,例如:
assets/images/logo.png
步骤二:配置
pubspec.yaml
打开
pubspec.yaml
,添加以下内容并取消注释缩进对齐:flutter: uses-material-design: true assets: - assets/images/logo.png # 或包含整个文件夹: # - assets/images/
注意:
缩进要使用空格(不能用 Tab)
图片路径对大小写敏感
步骤三:使用
Image.asset
显示图片Image.asset( 'assets/images/logo.png', width: 200, height: 100, fit: BoxFit.cover, // 控制缩放裁剪方式 )
使用网络图片(
Image.network
)Image.network( 'https://flutter.dev/images/flutter-logo-sharing.png', width: 200, height: 100, fit: BoxFit.contain, loadingBuilder: (context, child, progress) { if (progress == null) return child; return CircularProgressIndicator(); }, errorBuilder: (context, error, stackTrace) { return Icon(Icons.error); }, )
建议总是配
loadingBuilder
和errorBuilder
处理网络情况。图片控件常用属性
属性名 类型 说明 width
double
图片宽度 height
double
图片高度 fit
BoxFit
图片缩放裁剪方式,如 contain
、cover
color
Color
给图片加上颜色遮罩(配合 colorBlendMode
)repeat
ImageRepeat
图片重复方式(如 repeat-x) alignment
Alignment
图片对齐方式 图片裁剪、圆形、边框示例
圆形头像
ClipOval( child: Image.asset( 'assets/images/avatar.jpg', width: 100, height: 100, fit: BoxFit.cover, ), )
圆角图片
ClipRRect( borderRadius: BorderRadius.circular(12), child: Image.asset('assets/images/banner.jpg'), )
示例
class ImageExample extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("图片示例")), body: Column( children: [ Text("本地图片:"), Image.asset('assets/images/ic_launcher.png', width: 100), SizedBox(height: 20), Text("网络图片:"), Image.network( "https://www.163987.com/d/file/p/2023/05-12/01f170d69eace10455c7116e98290099.png", width: 100) ], )); } }
总结
目标 方法 加载项目中的图片 Image.asset('路径')
加载网络图片 Image.network('url')
加载本地文件图片 Image.file(File('路径'))
加载内存字节图片 Image.memory(Uint8List)
字体和图标配置
使用字体
步骤一:添加字体文件
在项目中创建字体目录:
assets/fonts/
放入字体文件,例如:
assets/fonts/Pacifico-Regular.ttf
步骤二:配置
pubspec.yaml
在
flutter:
区块下添加字体配置(注意缩进!):flutter: uses-material-design: true fonts: - family: Pacifico fonts: - asset: assets/fonts/Pacifico-Regular.ttf
步骤三:使用字体
Text( 'Hello 字体', style: TextStyle( fontFamily: 'Pacifico', fontSize: 32, ), )
使用内置图标(Material Icons)
Flutter 默认包含 Material Icons 图标库,只要:
flutter: uses-material-design: true
即可使用:
Icon(Icons.favorite, color: Colors.red)
pubspec.yaml 中资源声明
Flutter 中的
assets
是项目中包含的静态资源,例如:图片(PNG、JPG、SVG)
音频(MP3、WAV)
字体文件(TTF)
JSON / 文本 / 配置文件等
这些资源 必须在
pubspec.yaml
中显式声明 才能在应用中使用。声明单个文件
flutter: assets: - assets/images/logo.png
声明整个文件夹
flutter: assets: - assets/images/ - assets/audio/
注意事项
项 说明 缩进 必须是 2 个空格,不能用 Tab! 区分大小写 logo.PNG
≠logo.png
文件路径 必须真实存在,拼写要对 不支持通配 不能写成 assets/images/*.png
,只能手动列出或列目录修改后需 每次更改 assets
配置都应运行flutter pub get
或重启 IDE 使其生效