【Flutter Todo 实战】第四章:项目结构解析

· 6 min read

4.1 Flutter 项目的基本结构

当你创建一个新的 Flutter 项目时,会自动生成以下文件结构:

my_app/                          # 项目根目录
├── android/                     # Android 原生代码
├── ios/                         # iOS 原生代码
├── linux/                       # Linux 原生代码
├── macos/                       # macOS 原生代码
├── web/                         # Web 相关文件
├── windows/                     # Windows 原生代码
├── lib/                         # 🌟 Dart 代码(我们主要工作的地方)
│   └── main.dart               # 应用入口文件
├── test/                        # 测试代码
├── .gitignore                   # Git 忽略文件配置
├── analysis_options.yaml        # Dart 代码分析配置
├── pubspec.yaml                # 🌟 项目配置文件(依赖管理)
└── README.md                   # 项目说明文档

我们主要关注的目录

作为 Flutter 开发者,我们主要工作在以下两个文件/目录:

  1. pubspec.yaml - 配置项目信息和依赖
  2. lib/ - 编写 Dart 代码

4.2 pubspec.yaml 详解

pubspec.yaml 是 Flutter 项目的配置文件,相当于 Node.js 的 package.json 或 Python 的 requirements.txt

基础配置

1# 应用名称(只能用小写字母和下划线)
2name: todo_app
3
4# 应用描述
5description: A complete Flutter Todo application with Provider state management
6
7# 发布配置('none' 表示不发布到 pub.dev)
8publish_to: 'none'
9
10# 版本号:主版本.次版本.修订+构建号
11version: 1.0.0+1

环境配置

1# 指定 Dart SDK 版本范围
2environment:
3  sdk: '>=3.0.0 <4.0.0'

这表示项目需要 Dart 3.0.0 或更高版本,但低于 4.0.0。

依赖配置

1dependencies:
2  # Flutter SDK 本身
3  flutter:
4    sdk: flutter
5  
6  # 状态管理
7  provider: ^6.1.1
8  
9  # 本地存储
10  shared_preferences: ^2.2.2
11  
12  # UUID 生成
13  uuid: ^4.3.3
14  
15  # Material Design 图标
16  material_design_icons_flutter: ^7.0.7296

版本号说明:

写法 含义 示例
^1.2.3 兼容 1.2.3 及以上,但小于 2.0.0 ^6.1.1 → 6.1.1 到 6.x.x
>=1.2.0 大于等于 1.2.0 任何更新的版本
<2.0.0 小于 2.0.0 1.x.x 版本
1.2.3 固定版本 只能是 1.2.3

开发依赖

1dev_dependencies:
2  # 测试框架
3  flutter_test:
4    sdk: flutter
5  
6  # 代码规范检查
7  flutter_lints: ^3.0.1

开发依赖只在开发时使用,不会打包到最终应用中。

Flutter 特定配置

1flutter:
2  # 使用 Material Design 图标字体
3  uses-material-design: true
4  
5  # 资源文件(图片、字体等)
6  assets:
7    - assets/images/
8    - assets/icons/
9  
10  # 自定义字体
11  fonts:
12    - family: CustomFont
13      fonts:
14        - asset: assets/fonts/custom_font.ttf

安装依赖

修改 pubspec.yaml 后,运行以下命令安装依赖:

1flutter pub get

4.3 待办事项应用的项目结构

我们的待办事项应用采用了清晰的分层结构:

todo_app/
├── lib/                         # Dart 源代码
│   ├── main.dart               # 应用入口,主题配置
│   ├── models/                 # 数据模型层
│   │   └── task.dart          # 任务数据模型
│   ├── providers/              # 状态管理层
│   │   └── task_provider.dart # 任务状态管理
│   ├── services/               # 服务层
│   │   └── storage_service.dart # 本地存储服务
│   ├── screens/                # 页面层
│   │   └── home_screen.dart   # 主页面
│   └── widgets/                # 组件层
│       ├── task_item.dart     # 任务列表项
│       ├── add_task_dialog.dart # 添加任务对话框
│       ├── filter_chip_bar.dart # 筛选栏
│       └── empty_state.dart   # 空状态视图
├── pubspec.yaml               # 项目配置
└── ...

分层架构说明

┌─────────────────────────────────────┐
│           UI 层 (Widgets)           │  ← 用户界面
│   task_item, add_task_dialog...     │
├─────────────────────────────────────┤
│          页面层 (Screens)           │  ← 页面组织
│         home_screen.dart            │
├─────────────────────────────────────┤
│         状态层 (Providers)          │  ← 业务逻辑
│        task_provider.dart           │
├─────────────────────────────────────┤
│         服务层 (Services)           │  ← 数据持久化
│       storage_service.dart          │
├─────────────────────────────────────┤
│         模型层 (Models)             │  ← 数据结构
│          task.dart                  │
└─────────────────────────────────────┘

各层职责

1. Models(模型层)

职责: 定义数据结构

示例: task.dart 定义了任务的数据结构

class Task {
  final String id;
  final String title;
  final bool isCompleted;
  final DateTime createdAt;
  final DateTime? dueDate;
  
  // ...
}

2. Services(服务层)

职责: 处理数据持久化、网络请求等

示例: storage_service.dart 负责将任务保存到本地存储

class StorageService {
  static Future saveTasks(List tasks) async {
    // 保存到 SharedPreferences
  }
  
  static Future> loadTasks() async {
    // 从 SharedPreferences 读取
  }
}

3. Providers(状态层)

职责: 管理应用状态,处理业务逻辑

示例: task_provider.dart 管理任务列表的状态

class TaskProvider extends ChangeNotifier {
  List _tasks = [];
  
  void addTask(String title) {
    // 添加任务逻辑
    notifyListeners(); // 通知 UI 更新
  }
}

4. Screens(页面层)

职责: 组织页面结构,连接 UI 和状态

示例: home_screen.dart 是应用的主页面

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(...),
      body: TaskList(),
      floatingActionButton: AddButton(),
    );
  }
}

5. Widgets(组件层)

职责: 封装可复用的 UI 组件

示例: task_item.dart 封装了单个任务的显示样式

class TaskItem extends StatelessWidget {
  final Task task;
  
  @override
  Widget build(BuildContext context) {
    return ListTile(...);
  }
}

4.4 导入路径规则

在 Dart 中,导入文件有几种方式:

1. 导入 Dart/Flutter 内置库

import 'dart:convert';           // Dart 核心库
import 'package:flutter/material.dart';  // Flutter 库

2. 导入第三方包

import 'package:provider/provider.dart';
import 'package:uuid/uuid.dart';

3. 导入项目内文件

// 相对路径导入
import '../models/task.dart';
import '../providers/task_provider.dart';
import '../widgets/task_item.dart';

导入路径对照表

当前文件 导入目标 写法
lib/screens/home_screen.dart lib/models/task.dart import '../models/task.dart';
lib/widgets/task_item.dart lib/models/task.dart import '../models/task.dart';
lib/main.dart lib/screens/home_screen.dart import 'screens/home_screen.dart';
lib/providers/task_provider.dart lib/services/storage_service.dart import '../services/storage_service.dart';

4.5 命名规范

Flutter/Dart 社区有一些约定俗成的命名规范:

文件命名

  • 使用小写字母下划线
  • 单词之间用下划线分隔
✅ 好的命名:
  - task_item.dart
  - add_task_dialog.dart
  - storage_service.dart

❌ 不好的命名:
  - TaskItem.dart      # 不要用大写
  - addTaskDialog.dart # 不要用驼峰
  - task-item.dart     # 不要用连字符

类命名

  • 使用大驼峰命名法(PascalCase)
  • 每个单词首字母大写
✅ 好的命名:
class TaskProvider { }
class StorageService { }
class AddTaskDialog { }

❌ 不好的命名:
class taskProvider { }     # 首字母要小写
class storage_service { }  # 不要用下划线
class addTaskDialog { }    # 首字母要小写

变量和函数命名

  • 使用小驼峰命名法(camelCase)
  • 首字母小写,后续单词首字母大写
✅ 好的命名:
String taskTitle;
void addTask() { }
bool isCompleted;

❌ 不好的命名:
String TaskTitle;      # 首字母要小写
void add_task() { }    # 不要用下划线
bool is_completed;     # 不要用下划线

常量命名

  • 使用全大写下划线
✅ 好的命名:
const String TASKS_KEY = 'tasks';
const int MAX_TASK_COUNT = 100;

❌ 不好的命名:
const String tasksKey = 'tasks';  # 常量要用全大写

4.6 小结

目录/文件 作用
pubspec.yaml 项目配置和依赖管理
lib/main.dart 应用入口
lib/models/ 数据模型定义
lib/providers/ 状态管理
lib/services/ 数据持久化服务
lib/screens/ 页面组件
lib/widgets/ 可复用 UI 组件

这种分层结构的好处:

  1. 职责清晰 - 每层只做一件事
  2. 易于维护 - 修改一处不影响其他地方
  3. 便于测试 - 可以单独测试每层
  4. 代码复用 - 组件可以在多个页面使用

下一步第五章:数据模型详解

Related Articles