学习 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

  • 设置环境变量

    • 在系统环境变量中新建变量

      tex 复制代码
      变量名:PUB_HOSTED_URL
      变量值:https://pub.flutter-io.cn
      tex 复制代码
      变量名:FLUTTER_STORAGE_BASE_URL
      变量值:https://storage.flutter-io.cn
    • 在系统变量 PATH 中添加 Flutter bin目录

      tex 复制代码
      D:\flutter_windows_3.24.1-stable\flutter\bin
    • Android Studio 下载 SDK 工具和 Android SDK Comman-line Tools 并下载 Flutter 和 Dart 插件

    • 执行命令

      tex 复制代码
      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 结果

      powershell 复制代码
      [√] 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 仅依赖构造时传入的数据。

      dart 复制代码
      class HelloText extends StatelessWidget {
        final String name;
      
        const HelloText({super.key, required this.name});
      
        @override
        Widget build(BuildContext context) {
          return Text('Hello, $name');
        }
      }
    • StatefulWidget(有状态组件)

      StatefulWidget可变的 ,拥有自己的状态对象 State ,当状态改变时会触发 UI 重新构建 (setState())。

      适用场景:

      • UI 需要根据用户交互或数据更新而改变

      • 比如按钮点击计数、输入框内容、动画等。

      dart 复制代码
      class CounterWidget extends StatefulWidget {
        const CounterWidget({super.key});
      
        @override
        State<CounterWidget> createState() => _CounterWidgetState();
      }
      
      class _CounterWidgetState extends State<CounterWidget> {
        int _count = 0;
      
        void _increment() {
          setState(() {
            _count++;
          });
        }
      
        @override
        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,它们像"树枝"一样组成整个页面的布局和逻辑

      mathematica 复制代码
      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 内容为

    dart 复制代码
    import 'package:flutter/material.dart';
    
    void main() => runApp(const MyApp());
    
    class MyApp extends StatelessWidget {
      const MyApp();
    
      @override
      Widget build(BuildContext context) {
        return const MaterialApp(
          home: HelloWorldPage(),
        );
      }
    }
    
    class HelloWorldPage extends StatelessWidget {
      const HelloWorldPage();
    
      @override
      Widget build(BuildContext context) {
        return const Scaffold(
          body: Center(
            child: Text(
              'Hello World',
              style: TextStyle(fontSize: 24),
            ),
          ),
        );
      }
    }

5. Flutter 组件详解

5.1 基础组件

  • Text(文本显示)

    用于在界面中显示一段文本

    dart 复制代码
    Text('Hello Flutter')

    常用属性:

    属性名 类型 说明
    style TextStyle 设置字体大小、颜色、粗细、行高等
    textAlign TextAlign 文本对齐方式(如 centerleft
    maxLines int 显示的最大行数
    overflow TextOverflow 文本超出时的处理(如 ellipsis

    示例

    dart 复制代码
    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() 加载内存中的图片

    示例

    dart 复制代码
    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
       MyApp();
    
      @override
      Widget build(BuildContext context) {
        return  MaterialApp(
          home: HelloWorldPage(),
        );
      }
    }
    
    class HelloWorldPage extends StatelessWidget {
       HelloWorldPage();
    
      @override
      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 风格的图标

    基本用法

    dart 复制代码
    Icon(Icons.home)

    常用属性

    属性名 说明
    Icons.xxx 图标名,Flutter 内置许多图标
    size 图标大小
    color 图标颜色

    示例

    dart 复制代码
    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      MyApp();
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: HelloWorldPage(),
        );
      }
    }
    
    class HelloWorldPage extends StatelessWidget {
      HelloWorldPage();
    
      @override
      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 容器的几何变换(如旋转、缩放、平移)

    示例

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

      dart 复制代码
      import 'package:flutter/material.dart';
      
      void main() => runApp(MyApp());
      
      class MyApp extends StatelessWidget {
        MyApp();
      
        @override
        Widget build(BuildContext context) {
          return MaterialApp(
            home: HelloWorldPage(),
          );
        }
      }
      
      class HelloWorldPage extends StatelessWidget {
        HelloWorldPage();
      
        @override
        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)),
          );
        }
      }
    • 设置内边距和外边距

      dart 复制代码
      import 'package:flutter/material.dart';
      
      void main() => runApp(MyApp());
      
      class MyApp extends StatelessWidget {
        MyApp();
      
        @override
        Widget build(BuildContext context) {
          return MaterialApp(
            home: HelloWorldPage(),
          );
        }
      }
      
      class HelloWorldPage extends StatelessWidget {
        HelloWorldPage();
      
        @override
        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

    dart 复制代码
    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      MyApp();
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: HelloWorldPage(),
        );
      }
    }
    
    class HelloWorldPage extends StatelessWidget {
      HelloWorldPage();
    
      @override
      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('装饰效果')),
        );
      }
    }
  • 添加变换(旋转)

    dart 复制代码
    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      MyApp();
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: HelloWorldPage(),
        );
      }
    }
    
    class HelloWorldPage extends StatelessWidget {
      HelloWorldPage();
    
      @override
      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) 的布局组件。

    它的作用是:在子组件的外部(但在边框内部)增加空白区域

    语法结构

    dart 复制代码
    Padding(
      padding: EdgeInsets.all(8.0), // 设置内边距
      child: Text('Hello Padding'),
    )

    示例

  • 四边统一内边距

    dart 复制代码
    Padding(
      padding: EdgeInsets.all(16),
      child: Text('我有 16 的内边距'),
    )
  • 水平、垂直内边距不同

    dart 复制代码
    Padding(
      padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
      child: Text('左右 24,上下 12'),
    )
  • 仅指定某个方向

    dart 复制代码
    Padding(
      padding: EdgeInsets.only(top: 20, left: 10),
      child: Text('仅上边距 20,左边距 10'),
    )

    PaddingContainer 的区别

    特性 Padding Container
    设置内边距 专门用于设置内边距 (但只是组合属性的一部分)
    设置颜色、大小 不支持 可以设置宽高、颜色、装饰等
    推荐场景 专注间距控制 通用容器,做样式和布局控制更全面
  • Align(对齐)

    Align 是 Flutter 中用于 对子组件进行位置控制 的组件。它会在自身范围内,将 child 放置到指定的位置(例如居中、左上、右下等)

    基本语法

    dart 复制代码
    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) 表示正中间。"

    示例

    • 文字显示在右下角

      dart 复制代码
      Align(
        alignment: Alignment.bottomRight,
        child: Text('右下角文字'),
      )
    • 放一张图片到左上角

      dart 复制代码
      Align(
        alignment: Alignment.topLeft,
        child: Image.asset('assets/images/avatar.png', width: 60),
      )
    • 附加属性 widthFactorheightFactor

      这些属性可以影响 Align 本身的大小

      • widthFactor :子组件宽度 × 倍数,作为 Align 的宽度;

      • heightFactor :子组件高度 × 倍数,作为 Align 的高度;

      dart 复制代码
      Align(
            alignment: Alignment.center,
            widthFactor: 2,
            heightFactor: 2,
            child: Text('我是 2 倍大'),
          )
    • 和其他对齐组件的区别

      组件 功能描述
      Align 精确控制子组件在父组件中的位置
      Center 相当于 Align(alignment: Alignment.center)
      Padding 设置内边距,但不能控制子组件的具体位置
      Positioned 用于 Stack 中,绝对定位
  • Center(居中)

    Center 是一个非常简单的布局组件,它的作用是:将子组件放在父容器的中心位置

    基本语法

    dart 复制代码
    Center(
      child: Text('居中显示'),
    )

    它会自动让 Text 或其他子组件在父容器中 水平居中 + 垂直居中

    示例

    • 居中显示文本

      dart 复制代码
      Center(
        child: Text(
          'Hello Center',
          style: TextStyle(fontSize: 24),
        ),
      )
    • 居中显示图片

      dart 复制代码
      Center(
        child: Image.asset('assets/images/logo.png', width: 100),
      )
    • 结合 Container 使用

      dart 复制代码
      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 是一个横向布局组件,用于 将多个组件水平排列在一行内

    基本语法

    dart 复制代码
    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 子项之间空白完全相等

      示例

      dart 复制代码
      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 是一个 竖直方向布局组件 ,可以让多个子组件 从上到下一次排列

    基本语法

    dart 复制代码
    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 拉伸子组件到最大宽度

    示例

    • 简单垂直排布

      dart 复制代码
      Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: const [
              Text('标题'),
              SizedBox(height: 10),
              Text('副标题'),
              SizedBox(height: 10),
              Icon(Icons.star, size: 32),
            ],
          )
    • 加背景 + 居中演示(配合 Container)

      dart 复制代码
      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 轴 (前后)方向叠加在一起

    基本语法

    dart 复制代码
    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 vs Positioned

      • Stack 用来定义多个叠加的层

      • Positioned 用来对某个子组件进行绝定位

      和基本语法示例对比

      dart 复制代码
      Stack(
        children: [
          Container(color: Colors.yellow, width: 200, height: 200),
          Positioned(
            bottom: 10,
            right: 10,
            child: Text('右下角'),
          ),
        ],
      )
    • alignment:对非 Positioned 的子组件对齐

      dart 复制代码
      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 立体按钮

      dart 复制代码
      Container(
            child: Column(
              children: [
                ElevatedButton(
                  onPressed: () {
                    print('点击了 ElevatedButton');
                  },
                  child: Text('确定'),
                )
              ],
            ),
            color: Colors.white,
          )

      常用于强调主要操作,例如 "登录"、"提交"。

    • TextButton(纯文本按钮)

      dart 复制代码
      TextButton(
                  onPressed: () {
                    print('点击了 TextButton');
                  },
                  child: Text('取消'),
                )

      用于不那么显眼的按钮,比如"忘记密码"、"查看更多"。

    • OutlinedButton(带边框按钮)

      dart 复制代码
      OutlinedButton(
        onPressed: () {
          print('点击了 OutlinedButton');
        },
        child: Text('边框按钮'),
      )

      用于中性操作,比如"跳过"、"稍后再说"。

    • 自定义按钮样式

      三种按钮都支持使用 style 参数来自定义外观,使用 ButtonStyle

      dart 复制代码
      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)

    基本语法

    dart 复制代码
    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) 双指缩放

    示例

    • 点击、长按、双击事件

      dart 复制代码
      GestureDetector(
        onTap: () => print('点击'),
        onDoubleTap: () => print('双击'),
        onLongPress: () => print('长按'),
        child: Container(
          padding: EdgeInsets.all(20),
          color: Colors.lightGreen,
          child: Text('点我试试'),
        ),
      )
    • 拖动(onPanUpdate)

      dart 复制代码
      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)

      dart 复制代码
      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 组件作为"水波纹的绘制容器"

    基本用法

    dart 复制代码
    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 使用 (必须)

      dart 复制代码
      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 是最常用的文本输入组件,用于实现表单的输入、搜索框、聊天框等各种输入功能

    基本用法

    dart 复制代码
    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 是否只读

    示例

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

      dart 复制代码
      class TextFieldExample extends StatelessWidget {
        final TextEditingController _controller = TextEditingController();
      
        @override
        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('提交'))
                ],
              ),
            ),
          );
        }
      }
    • 密码框(隐藏输入)

      dart 复制代码
      TextField(
                    obscureText: true,
                    decoration: InputDecoration(
                      labelText: '密码',
                      border: OutlineInputBorder(),
                    ),
                  )

      不同输入类型

      输入类型 示例设置
      文本(默认) keyboardType: TextInputType.text
      数字 keyboardType: TextInputType.number
      电话 keyboardType: TextInputType.phone
      邮箱 keyboardType: TextInputType.emailAddress
    • 多行输入

      dart 复制代码
      TextField(
        maxLines: 5,
        decoration: InputDecoration(labelText: '多行备注'),
      )
    • 自定义装饰 InputDecoration 示例

      dart 复制代码
      TextField(
        decoration: InputDecoration(
          prefixIcon: Icon(Icons.person),
          suffixIcon: Icon(Icons.clear),
          labelText: '用户名',
          hintText: '请输入用户名',
          border: OutlineInputBorder(),
        ),
      )
  • Checkbox(多选框)

    Checkbox 是一个可以勾选/取消的组件,只有两个状态(true / false ) 可以搭配文字或图标一起使用。

    基本用法

    dart 复制代码
    bool _isChecked = false;
    
    Checkbox(
      value: _isChecked,
      onChanged: (bool? value) {
        setState(() {
          _isChecked = value!;
        });
      },
    )

    必须在 StatefulWidget 中使用,因为复选框的值需要动态更新。

    示例

    dart 复制代码
    class CheckBoxDemo extends StatefulWidget {
      @override
      _CheckBoxDemoState createState() => _CheckBoxDemoState();
    }
    
    class _CheckBoxDemoState extends State<CheckBoxDemo> {
      bool _isSelected = false;
    
      @override
      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 (复选框 + 标题 + 子标题)

    dart 复制代码
    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 一起使用。

    最基本的用法示例

    dart 复制代码
    Radio<int>(
      value: 1,
      groupValue: _selectedValue,
      onChanged: (int? value) {
        setState(() {
          _selectedValue = value!;
        });
      },
    )
    • value:表示当前这个单选按钮的值

    • groupValue:表示当前"选中的值"

    • onChanged:当点击时调用,传入的就是 value

    选择性别示例:

    dart 复制代码
    class RadioDemo extends StatefulWidget {
      @override
      _RadioDemoState createState() => _RadioDemoState();
    }
    
    class _RadioDemoState extends State<RadioDemo> {
      String _gender = "男";
    
      @override
      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 (关闭)

    最基本的用法

    dart 复制代码
    bool _isOn = false;
    
    Switch(
      value: _isOn,
      onChanged: (bool value) {
        setState(() {
          _isOn = value;
        });
      },
    )

    必须在 StatefulWidget 中使用,因为开关状态需要实时更新。

    示例:

    • 控制某功能开关

      dart 复制代码
      class SwitchDemo extends StatefulWidget {
        @override
        _SwitchDemoState createState() => _SwitchDemoState();
      }
      
      class _SwitchDemoState extends State<SwitchDemo> {
        bool _isDarkMode = false;
      
        @override
        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 中,FormFormField 是用于统一管理多个输入组件的表单系统,可以方便地进行表单验证、提交等操作,常用于登录、注册、反馈等界面。

    • 什么是 FormFormField

      组件 作用说明
      Form 表单容器,用于管理一组输入项(字段)
      FormField 表单字段的基类(如 TextFormField)

      TextFormField 是最常用的 FormField 实现,是带表单验证功能的输入框

    • Form 的基本结构

      dart 复制代码
      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() 重置所有字段内容和状态
    • 完整示例

      dart 复制代码
      class FormExample extends StatefulWidget {
        @override
        _FormExampleState createState() => _FormExampleState();
      }
      
      class _FormExampleState extends State<FormExample> {
        final _formKey = GlobalKey<FormState>();
        String _username = '';
        String _password = '';
      
        @override
        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

      区别项 TextField TextFormField
      表单验证支持 无验证方法 支持 validator/onSaved 等
      与 Form 配合使用 需要单独管理状态 可统一使用 Form 管理
      推荐使用场景 简单输入框 表单场景(如登录、注册等)
    • 一些常用方法(FormState)

      方法名 说明
      validate() 所有字段验证,返回布尔值
      save() 调用每个字段的 onSaved()
      reset() 重置整个表单

5.5 滚动视图

  • ListView(列表)

    ListView 是一个 可滚动的线性列表视图组件 可以直接或水平显示一系列子组件

    • 最基本的用法

      dart 复制代码
      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 设置内边距
    • 示例

      dart 复制代码
      class ListViewDemo extends StatelessWidget {
        final List<String> items = List.generate(20, (index) => '项目 $index');
      
        @override
        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(常规固定列数网格)

        dart 复制代码
        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(推荐用于大数据列表)

        dart 复制代码
        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(指定最大宽度自动适配列数)

        dart 复制代码
        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 滚动行为(常用于嵌套时禁用滚动)
    • 示例

      dart 复制代码
      import 'package:flutter/material.dart';
      
      class GridViewExample extends StatelessWidget {
        @override
        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)错误。

    • 基本用法

      dart 复制代码
      SingleChildScrollView(
        child: Column(
          children: [
            Text('A'),
            Text('B'),
            Text('C'),
            // 很多内容...
          ],
        ),
      )

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

    • 典型使用场景

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

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

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

    • 重要属性说明

      属性名 类型 说明
      scrollDirection Axis 滚动方向,默认是 Axis.vertical
      padding EdgeInsets 内边距
      reverse bool 是否反向滚动
      physics ScrollPhysics 滚动行为(如弹性、不可滚动)
      controller ScrollController 控制滚动、监听滚动位置等
    • 示例

      dart 复制代码
      import 'package:flutter/material.dart';
      
      class ScrollDemo extends StatelessWidget {
        @override
        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 通常配合 MaterialPageRoutenamed route 使用。

    • 最基础的页面跳转方式

      • 跳转到新页面(push)

        dart 复制代码
        Navigator.push(
          context,
          MaterialPageRoute(builder: (context) => SecondPage()),
        );
      • 返回上一级页面(pop)

        dart 复制代码
        Navigator.pop(context);
    • 带返回值的页面跳转

      A → B,B返回数据给A:

      在 A 页面:

      dart 复制代码
      void _goToSecondPage() async {
        final result = await Navigator.push(
          context,
          MaterialPageRoute(builder: (context) => SecondPage()),
        );
        print("从第二页返回的数据: $result");
      }

      在 B 页面:

      dart 复制代码
      ElevatedButton(
        onPressed: () {
          Navigator.pop(context, "这是返回值");
        },
        child: Text("返回并携带数据"),
      )
    • 使用命名路由(推荐方式)

      • 定义路由表

        dart 复制代码
        MaterialApp(
          initialRoute: '/',
          routes: {
            '/': (context) => HomePage(),
            '/second': (context) => SecondPage(),
          },
        )
      • 跳转方式

        dart 复制代码
        Navigator.pushNamed(context, '/second');
      • 返回方式

        dart 复制代码
        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()

      作用:** 打开(压栈)一个新页面**

      dart 复制代码
      Navigator.push(
        context,
        MaterialPageRoute(builder: (context) => SecondPage()),
      );
      • context:当前页面的上下文

      • MaterialPageRoute:常用的页面过渡动画(安卓风格)

      • SecondPage():你要跳转的新页面 Widget

      示例

      dart 复制代码
      ElevatedButton(
        onPressed: () {
          Navigator.push(
            context,
            MaterialPageRoute(builder: (context) => SecondPage()),
          );
        },
        child: Text("去第二页"),
      )
    • Navigator.pop()

      作用:返回(出栈)上一个页面

      dart 复制代码
      Navigator.pop(context);

      可选地返回一个值:

      dart 复制代码
      Navigator.pop(context, "返回的数据");
    • push + pop 结合使用(带返回值)

      • 第一个页面

        dart 复制代码
        void _goToSecondPage() async {
          final result = await Navigator.push(
            context,
            MaterialPageRoute(builder: (context) => SecondPage()),
          );
        
          print("从第二页返回的数据是:$result");
        }
      • 第二个页面

        dart 复制代码
        ElevatedButton(
          onPressed: () {
            Navigator.pop(context, "你好,这是返回值");
          },
          child: Text("返回并传数据"),
        )
    • Navigator 的"堆栈"原理图示

      scss 复制代码
      初始:
      [ 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 应用中几乎每个页面都会使用的标准导航栏。

    • 基本语法

      dart 复制代码
      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
    • 示例

      dart 复制代码
      import 'package:flutter/material.dart';
      
      class AppBarExample extends StatelessWidget {
        @override
        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 部件放进去就可以构成完整的页面。

    • 基本使用方式

      dart 复制代码
      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 页面底部悬浮层
    • 示例

      dart 复制代码
      import 'package:flutter/material.dart';
      
      class ScaffoldExample extends StatelessWidget {
        @override
        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 提供的一个侧边导航菜单,通常从左边滑出,用于展示导航选项、用户信息等。

    • 基本结构

      dart 复制代码
      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)

      • 手动打开

        dart 复制代码
        Scaffold.of(context).openDrawer(); // 仅限于在子 Widget 中使用 Builder 包裹
      • 手动关闭

        dart 复制代码
        Navigator.pop(context)
    • 示例

      dart 复制代码
      class DrawerExample extends StatelessWidget {
        @override
        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)

    • 基本用法

      dart 复制代码
      Scaffold(
        bottomNavigationBar: BottomNavigationBar(
          currentIndex: 0, // 当前选中索引
          onTap: (index) {
            // 切换页面逻辑
          },
          items: [
            BottomNavigationBarItem(
              icon: Icon(Icons.home),
              label: '首页',
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.person),
              label: '我的',
            ),
          ],
        ),
      )
    • 示例

      dart 复制代码
      import 'package:flutter/material.dart';
      
      class BottomNavExample extends StatefulWidget {
        @override
        _BottomNavExampleState createState() => _BottomNavExampleState();
      }
      
      class _BottomNavExampleState extends State<BottomNavExample> {
        int _currentIndex = 0;
      
        final List<Widget> _pages = [
          Center(child: Text('首页内容')),
          Center(child: Text('分类内容')),
          Center(child: Text('我的内容'))
        ];
      
        @override
        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会自动刷新 展示新的内容,

比如:

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

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

  3. 一个页面当前是"加载中"还是"已完成"是状态(loading = true / false

示例

dart 复制代码
int count = 0; // 这就是一个状态

ElevatedButton(
  onPressed: () {
    setState(() {
      count++;
    });
  },
  child: Text('点击了 $count 次'),
)
  • Flutter 中状态是怎么驱动 UI 的?

    Flutter 的 Widget 是声明时UI,它不是手动改动控件,而是重新构建:

    dart 复制代码
    // 当状态改变时
    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 目录

        在项目根目录下创建文件夹:

        bash 复制代码
        /assets/images/

        放入图片,例如:

        bash 复制代码
        assets/images/logo.png
      • 步骤二:配置 pubspec.yaml

        打开 pubspec.yaml ,添加以下内容并取消注释缩进对齐:

        yaml 复制代码
        flutter:
          uses-material-design: true
        
          assets:
            - assets/images/logo.png
            # 或包含整个文件夹:
            # - assets/images/

        注意:

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

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

      • 步骤三:使用 Image.asset 显示图片

        dart 复制代码
        Image.asset(
          'assets/images/logo.png',
          width: 200,
          height: 100,
          fit: BoxFit.cover, // 控制缩放裁剪方式
        )
    • 使用网络图片(Image.network)

      dart 复制代码
      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 处理网络情况。

    • 图片控件常用属性

      属性名 类型 说明
      width double 图片宽度
      height double 图片高度
      fit BoxFit 图片缩放裁剪方式,如 containcover
      color Color 给图片加上颜色遮罩(配合 colorBlendMode
      repeat ImageRepeat 图片重复方式(如 repeat-x)
      alignment Alignment 图片对齐方式
    • 图片裁剪、圆形、边框示例

      • 圆形头像

        dart 复制代码
        ClipOval(
          child: Image.asset(
            'assets/images/avatar.jpg',
            width: 100,
            height: 100,
            fit: BoxFit.cover,
          ),
        )
      • 圆角图片

        dart 复制代码
        ClipRRect(
          borderRadius: BorderRadius.circular(12),
          child: Image.asset('assets/images/banner.jpg'),
        )
    • 示例

      dart 复制代码
      class ImageExample extends StatelessWidget {
        @override
        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)
  • 字体和图标配置

    • 使用字体

      • 步骤一:添加字体文件

        在项目中创建字体目录:

        bash 复制代码
        assets/fonts/

        放入字体文件,例如:

        bash 复制代码
        assets/fonts/Pacifico-Regular.ttf
      • 步骤二:配置 pubspec.yaml

        flutter: 区块下添加字体配置(注意缩进!):

        yaml 复制代码
        flutter:
          uses-material-design: true
        
          fonts:
            - family: Pacifico
              fonts:
                - asset: assets/fonts/Pacifico-Regular.ttf
      • 步骤三:使用字体

        dart 复制代码
        Text(
          'Hello 字体',
          style: TextStyle(
            fontFamily: 'Pacifico',
            fontSize: 32,
          ),
        )
    • 使用内置图标(Material Icons)

      Flutter 默认包含 Material Icons 图标库,只要:

      yaml 复制代码
      flutter:
        uses-material-design: true

      即可使用:

      dart 复制代码
      Icon(Icons.favorite, color: Colors.red)
  • pubspec.yaml 中资源声明

    Flutter 中的 assets 是项目中包含的静态资源,例如:

    • 图片(PNG、JPG、SVG)

    • 音频(MP3、WAV)

    • 字体文件(TTF)

    • JSON / 文本 / 配置文件等

    这些资源 必须在 pubspec.yaml 中显式声明 才能在应用中使用。

    • 声明单个文件

      yaml 复制代码
      flutter:
        assets:
          - assets/images/logo.png
    • 声明整个文件夹

      yaml 复制代码
      flutter:
        assets:
          - assets/images/
          - assets/audio/
    • 注意事项

      说明
      缩进 必须是 2 个空格,不能用 Tab!
      区分大小写 logo.PNGlogo.png
      文件路径 必须真实存在,拼写要对
      不支持通配 不能写成 assets/images/*.png,只能手动列出或列目录
      修改后需 每次更改 assets 配置都应运行 flutter pub get 或重启 IDE 使其生效
相关推荐
火柴就是我36 分钟前
让我们实现一个更好看的内部阴影按钮
android·flutter
王晓枫1 小时前
flutter接入三方库运行报错:Error running pod install
前端·flutter
砖厂小工7 小时前
用 GLM + OpenClaw 打造你的 AI PR Review Agent — 让龙虾帮你审代码
android·github
张拭心8 小时前
春节后,有些公司明确要求 AI 经验了
android·前端·人工智能
张拭心8 小时前
Android 17 来了!新特性介绍与适配建议
android·前端
shankss9 小时前
Flutter 下拉刷新库 pull_to_refresh_plus 设计与实现分析
flutter
Kapaseker10 小时前
Compose 进阶—巧用 GraphicsLayer
android·kotlin
黄林晴11 小时前
Android17 为什么重写 MessageQueue
android
忆江南1 天前
iOS 深度解析
flutter·ios
明君879971 天前
Flutter 实现 AI 聊天页面 —— 记一次 Markdown 数学公式显示的踩坑之旅
前端·flutter