学习 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 使其生效
相关推荐
小李飞飞砖39 分钟前
Sophix、Tinker 和 Robust 三大主流 Android 热修复框架的详细对比
android
future14121 小时前
游戏开发日记
数据结构·学习·c#
TE-茶叶蛋1 小时前
Flutter、Vue 3 和 React 在 UI 布局比较
vue.js·flutter·react.js
感觉不怎么会2 小时前
Android 12 - 部分相机横屏显示方案
android
棱镜研途2 小时前
学习笔记丨卷积神经网络(CNN):原理剖析与多领域Github应用
图像处理·笔记·学习·计算机视觉·cnn·卷积神经网络·信号处理
皮蛋sol周3 小时前
嵌入式学习C语言(八)二维数组及排序算法
c语言·学习·算法·排序算法
怀君3 小时前
Flutter——数据库Drift开发详细教程之迁移(九)
数据库·flutter
GeniuswongAir3 小时前
如何在Flutter开发中系统性减少知识盲区
flutter
fundroid4 小时前
Swift 进军 Android,Kotlin 该如何应对?
android·ios