当前位置: 首页 > news >正文

学习 Flutter (一)

学习 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 appsX 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')),],);}
      }
      

    区别总结

    特性StatelessWidgetStatefulWidget
    状态是否可变否(不可变)是(可变)
    是否持有状态对象是(通过 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')
    

    常用属性:

    属性名类型说明
    styleTextStyle设置字体大小、颜色、粗细、行高等
    textAlignTextAlign文本对齐方式(如 centerleft
    maxLinesint显示的最大行数
    overflowTextOverflow文本超出时的处理(如 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 组合体。

    常用属性

    属性类型说明
    childWidget子组件
    width / heightdouble设置容器的宽度和高度
    marginEdgeInsets外边距
    paddingEdgeInsets内边距(对子组件生效)
    colorColor背景颜色(不能与 decoration.color 同时使用)
    alignmentAlignment控制子组件在容器内的位置
    decorationBoxDecoration背景装饰(如圆角、边框、背景图等)
    transformMatrix4容器的几何变换(如旋转、缩放、平移)

    示例

    • 设置宽高 + 背景色 + 子组件居中

      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'),
    )
    

    PaddingContainer 的区别

    特性PaddingContainer
    设置内边距专门用于设置内边距(但只是组合属性的一部分)
    设置颜色、大小不支持可以设置宽高、颜色、装饰等
    推荐场景专注间距控制通用容器,做样式和布局控制更全面
  • 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),
      )
      
    • 附加属性 widthFactorheightFactor

      这些属性可以影响 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增加空白区域,但不控制对齐方式
      PositionedStack 中做绝对定位需要配合 Stack 使用
  • Row(水平排列)

    Row 是一个横向布局组件,用于 将多个组件水平排列在一行内

    基本语法

    Row(children: [Text('A'),Text('B'),Text('C'),],
    )
    

    这段代码会将 A B C 横向排在一行里。

    • 常用属性详情

      属性名类型说明
      childrenList<Widget>子组件列表
      mainAxisAlignmentMainAxisAlignment主轴(水平方向)对齐方式
      crossAxisAlignmentCrossAxisAlignment交叉轴(垂直方向)对齐方式
      mainAxisSizeMainAxisSize主轴尺寸:最大/最小(是否占满可用空间)
      textDirectionTextDirection布局方向:从左到右(默认)还是从右到左
    • 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('第三行'),],
    )
    
    • 常用属性解释

      属性名类型说明
      childrenList<Widget>子组件列表
      mainAxisAlignmentMainAxisAlignment主轴(竖直方向)对齐方式
      crossAxisAlignmentCrossAxisAlignment交叉轴(水平方向)对齐方式
      mainAxisSizeMainAxisSize主轴大小控制(是否占满可用垂直空间)
    • 主轴对齐(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),),],
    )
    
    • 常用属性解释

      属性名类型说明
      childrenList<Widget>所有子组件,越靠后越在上层
      alignmentAlignment控制非 Positioned 子组件的位置
      fitStackFit控制子组件尺寸如何适应 Stack
      clipBehaviorClip是否裁剪超出部分(默认 Clip.hardEdge
    • Stack vs Positioned

      • 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('点我'),),
    )
    
    • 常用事件一览

      属性名类型说明
      onTapvoid Function()单击
      onDoubleTapvoid Function()双击
      onLongPressvoid Function()长按
      onPanUpdateFunction(DragUpdateDetails)拖动时触发(全向)
      onPanStart / onPanEnd-拖动开始 / 结束
      onScaleUpdateFunction(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('点我'),),
    )
    

    点击时会看到水波纹从点击点扩散开来

    • 常用属性

      属性名类型说明
      onTapvoid Function()?点击事件
      onDoubleTapvoid Function()?双击事件
      onLongPressvoid Function()?长按事件
      borderRadiusBorderRadius设置水波纹圆角
      splashColorColor设置水波纹颜色
      highlightColorColor按下时的背景色
      childWidget显示内容
    • 配合 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 区别对比

      对比点GestureDetectorInkWell
      是否有视觉反馈无水波纹有水波纹
      是否依赖 Material不依赖必须依赖 Material 父组件
      支持的手势种类拖动、缩放、滑动等更丰富主要用于点击相关
      使用场景自定义复杂交互通常用于按钮、卡片、列表点击反馈等

5.4 输入框和表单

  • TextField(文本输入)

    TextField 是最常用的文本输入组件,用于实现表单的输入、搜索框、聊天框等各种输入功能

    基本用法

    TextField(decoration: InputDecoration(labelText: '用户名',hintText: '请输入用户名',border: OutlineInputBorder(),),
    )
    

    效果:一个带标签、提示文字、边框的输入框

    • 常用属性详情

      属性名类型说明
      controllerTextEditingController控制和监听输入框内容
      decorationInputDecoration装饰输入框(如提示、图标、边框等)
      obscureTextbool是否隐藏输入内容(用于密码)
      keyboardTypeTextInputType输入类型(文本、数字、邮箱等)
      maxLinesint输入框最大行数
      onChangedFunction(String)文本改变时回调
      onSubmittedFunction(String)用户按下“完成/提交”时的回调
      enabledbool是否可编辑
      readOnlybool是否只读

    示例

    • 带控制器示例(获取输入内容)

      
      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 ? "已选中" : "未选中"),],),),);}
    }

    常用属性

    属性名类型说明
    valuebool当前是否勾选
    onChanged(bool?) → void勾选状态变化时的回调函数
    activeColorColor选中时的颜色
    checkColorColor号颜色
    tristatebool是否支持三种状态(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 + TextCheckboxListTile
    支持不确定(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"),],),);}
    }
    

    常用属性一览

    属性名类型说明
    valueT当前这个选项的值
    groupValueT当前组中被选中的值
    onChangedFunction(T?)点击时回调
    activeColorColor选中状态颜色
    toggleablebool是否支持再次点击取消(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 ? '暗黑模式已开启' : '暗黑模式已关闭'),],),);}
      }

    常用属性

    属性名类型说明
    valuebool当前开关状态
    onChanged(bool) → void状态变化回调函数
    activeColorColor开启时的主色(圆点颜色)
    activeTrackColorColor开启时轨道颜色
    inactiveThumbColorColor关闭时圆点颜色
    inactiveTrackColorColor关闭时轨道颜色
    materialTapTargetSizeMaterialTapTargetSize调整点击区域大小
  • Form 与 FormField(表单管理)

    在 Flutter 中,FormFormField 是用于统一管理多个输入组件的表单系统,可以方便地进行表单验证、提交等操作,常用于登录、注册、反馈等界面。

    • 什么是 FormFormField

      组件作用说明
      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 VS TextFormField

      区别项TextFieldTextFormField
      表单验证支持无验证方法支持 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: 高级自定义构造(极少用)

    • 常用属性

      属性名类型说明
      itemCountint列表项数量(用于 builder)
      itemBuilderIndexedWidgetBuilder构建每项内容的方法
      scrollDirectionAxis滚动方向(Axis.vertical / horizontal
      reversebool是否反转列表显示顺序
      shrinkWrapbool是否根据内容自动收缩高度
      physicsScrollPhysics滚动行为(如禁止、弹性等)
      paddingEdgeInsets设置内边距
    • 示例

      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'),);}),
        )
    • 常用属性说明

      属性名类型说明
      crossAxisCountint每行显示的列数
      mainAxisSpacingdouble每行之间的间距(垂直方向)
      crossAxisSpacingdouble每列之间的间距(水平方向)
      childAspectRatiodouble宽高比(宽/高)
      shrinkWrapbool是否根据内容高度自适应(适用于嵌套)
      physicsScrollPhysics滚动行为(常用于嵌套时禁用滚动)
    • 示例

      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'),// 很多内容...],),
      )

      SingleChildScrollViewchild 只能是 一个 Widget,通常搭配 Column 使用。

    • 典型使用场景

      • 登录页 / 注册页(键盘弹出时防止布局溢出)

      • 表单页面(需要整体滚动)

      • 多控件组合的页面(不是列表)

    • 重要属性说明

      属性名类型说明
      scrollDirectionAxis滚动方向,默认是 Axis.vertical
      paddingEdgeInsets内边距
      reversebool是否反向滚动
      physicsScrollPhysics滚动行为(如弹性、不可滚动)
      controllerScrollController控制滚动、监听滚动位置等
    • 示例

      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 区别对比

      对比项SingleChildScrollViewListView
      用法场景多个固定控件、表单页面长列表、动态项
      性能优化没有懒加载,所有内容一次性渲染支持懒加载
      子组件结构一个 Widget(如 Column)包多个控件多个 Widget 构建
      嵌套使用更适合嵌套在页面中或布局中嵌套需注意高度限制和滚动冲突

5.6 导航和路由

  • Navigator 介绍

    Navigator 是用于管理页面(Route)跳转和堆栈操作的组件,类似网页的前进、后退、跳转操作。

    • 什么是 Navigator ?

      Navigator 是一个页面堆栈管理器,你可以:

      • push:打开新页面(入栈)

      • pop:返回上一个页面(出栈)

      • replace:替换当前页面

      • 清空所有页面再跳转:跳转并清空历史

      Navigator 通常配合 MaterialPageRoutenamed 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

    pushpop 是 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('内容')),
      )
    • 常用属性说明

      属性名类型作用说明
      titleWidget应用栏的标题,通常是 Text
      leadingWidget左侧图标(默认是返回箭头)
      actionsList<Widget>右侧图标按钮列表
      backgroundColorColor背景颜色
      centerTitlebool是否居中标题(iOS 默认为 true)
      elevationdouble阴影高度(默认 4)
      bottomPreferredSizeWidget下方扩展区域,如 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 的常用属性详解

      属性名类型作用说明
      appBarAppBar页面顶部导航栏
      bodyWidget页面主要内容区域
      floatingActionButtonFloatingActionButton页面悬浮按钮
      drawerDrawer左侧滑出菜单
      bottomNavigationBarBottomNavigationBar页面底部导航栏
      backgroundColorColor页面背景色
      persistentFooterButtonsList<Widget>固定在底部的按钮组
      bottomSheetWidget页面底部悬浮层
    • 示例

      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 or BottomAppBar
      显示提示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: "我的"),],),);}
      }
    • 属性说明

      属性名类型说明
      itemsList菜单项(最少2项)
      currentIndexint当前选中项的索引
      onTapFunction(int)点击导航项回调
      typeBottomNavigationBarType显示样式:fixed(默认)或 shifting(动效)
      selectedItemColorColor选中项颜色
      unselectedItemColorColor未选中项颜色
      backgroundColorColor背景色

6. 状态管理基础

6.1 什么是状态?

简单来说,状态就是某个变量的值 当这个值发生变化时,对应的 UI会自动刷新 展示新的内容,

比如:

  1. 一个计数器的数字是状态 (count = 3)

  2. 一个按钮是否选中是状态(isSelected = true

  3. 一个页面当前是“加载中”还是“已完成”是状态(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: trueassets:- assets/images/logo.png# 或包含整个文件夹:# - assets/images/
        

        注意:

        1. 缩进要使用空格(不能用 Tab)

        2. 图片路径对大小写敏感

      • 步骤三:使用 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);},
      )
      

      建议总是配 loadingBuildererrorBuilder 处理网络情况。

    • 图片控件常用属性

      属性名类型说明
      widthdouble图片宽度
      heightdouble图片高度
      fitBoxFit图片缩放裁剪方式,如 containcover
      colorColor给图片加上颜色遮罩(配合 colorBlendMode
      repeatImageRepeat图片重复方式(如 repeat-x)
      alignmentAlignment图片对齐方式
    • 图片裁剪、圆形、边框示例

      • 圆形头像

        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: truefonts:- family: Pacificofonts:- 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.PNGlogo.png
      文件路径必须真实存在,拼写要对
      不支持通配不能写成 assets/images/*.png,只能手动列出或列目录
      修改后需每次更改 assets 配置都应运行 flutter pub get 或重启 IDE 使其生效
http://www.dtcms.com/a/272944.html

相关文章:

  • html的outline: none;
  • C++STL-deque
  • 1. COLA-DDD的实战
  • 【基础架构】——软件系统复杂度的来源(低成本、安全、规模)
  • 告别卡顿与慢响应!现代 Web 应用性能优化:从前端渲染到后端算法的全面提速指南
  • IDEA运行Spring项目报错:java: 警告: 源发行版 17 需要目标发行版 17,java: 无效的目标发行版: 17
  • Cargo.toml 配置详解
  • 【科研绘图系列】R语言探索生物多样性与地理分布的可视化之旅
  • 网安-解决pikachu-rce乱码问题
  • 访问Windows服务器备份SQL SERVER数据库
  • (C++)任务管理系统(文件存储)(正式版)(迭代器)(list列表基础教程)(STL基础知识)
  • x86交叉编译ros 工程给jetson nano运行
  • Rust and the Linux Kernel
  • Sophix、Tinker 和 Robust 三大主流 Android 热修复框架的详细对比
  • windows10 安装docker到H盘
  • Linux 服务器挖矿病毒深度处理与防护指南
  • 使用Docker将Python项目部署到云端的完整指南
  • Web 会话认证方案详解:原理、流程与安全实践
  • Variables
  • 分库分表之实战-sharding-JDBC分库分表执行流程原理剖析
  • ubantu问题手册
  • 大数据学习5:网站访问日志分析
  • 力扣hot100速通(7.9)|49.字母异位词分组 128.最长连续序列 283.移动零 11.盛最多水的容器 42.接雨水
  • 观成科技:基于自监督学习技术的恶意加密流量检测方案
  • CRMEB Pro版前端环境配置指南
  • AT9850B北斗双频导航定位芯片简介
  • 基于大数据的电力系统故障诊断技术研究
  • 华为鸿蒙HarmonyOpenEye项目:开眼App的鸿蒙实现之旅
  • SSRF(ctfshow)
  • 【第三章-基础】Python 字典