Flutter 小白入门教程Flutter 小白入门教程
首页
学习指南
项目实战
Flutter 官网
编程指南
首页
学习指南
项目实战
Flutter 官网
编程指南
  • 入门基础

    • 📚 基础教程
    • 第1章 - 认识 Flutter
    • 第2章 - 环境搭建
    • 第3章 - Dart 语言基础
    • 第4章 - 第一个 Flutter 应用
    • 第5章 - Widget 基础
    • 第6章 - 布局系统
    • 第7章 - 状态管理入门
    • 第8章 - 页面导航
    • 第9章 - 资源管理
  • 进阶开发

    • 第10章 - 网络请求
    • 第11章 - 本地存储
    • 第12章 - 对话框与反馈
    • 第13章 - 列表进阶
    • 第14章 - 主题定制
    • 第15章 - 状态管理进阶
    • 第16章 - 动画入门
    • 第17章 - 常用第三方包
  • 调试与发布

    • 第18章 - 调试与性能优化
    • 第19章 - 打包与发布
  • 附录

    • 附录A - UI 框架与组件库推荐
    • 附录B - 项目结构最佳实践
    • 附录C - 国际化配置
    • 附录D - 权限处理

附录B - 项目结构最佳实践

嗨,朋友!我是长安。

当你的 Flutter 项目越来越大时,良好的项目结构就变得尤为重要。它能让你的代码更易读、更易维护、更易扩展。

这一章,我会介绍从小型到大型项目的结构组织方式,以及常用的架构模式!

📁 小型项目结构

适合个人项目、Demo 或功能简单的 App。

my_app/
├── lib/
│   ├── main.dart              # 入口文件
│   ├── pages/                 # 页面
│   │   ├── home_page.dart
│   │   ├── login_page.dart
│   │   └── profile_page.dart
│   ├── widgets/               # 自定义组件
│   │   ├── custom_button.dart
│   │   └── user_card.dart
│   ├── models/                # 数据模型
│   │   └── user.dart
│   ├── services/              # 服务(网络、存储等)
│   │   └── api_service.dart
│   └── utils/                 # 工具类
│       └── constants.dart
├── assets/                    # 资源文件
│   ├── images/
│   └── fonts/
├── test/                      # 测试
└── pubspec.yaml

示例代码

// lib/main.dart
import 'package:flutter/material.dart';
import 'pages/home_page.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My App',
      theme: ThemeData(
        useMaterial3: true,
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
      ),
      home: const HomePage(),
    );
  }
}
// lib/pages/home_page.dart
import 'package:flutter/material.dart';
import '../widgets/user_card.dart';
import '../services/api_service.dart';

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final _apiService = ApiService();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('首页')),
      body: const Center(child: Text('Hello')),
    );
  }
}

📂 中型项目结构

适合有一定规模的项目,引入了状态管理和更细致的分层。

my_app/
├── lib/
│   ├── main.dart
│   ├── app.dart               # App 配置(主题、路由等)
│   │
│   ├── config/                # 配置
│   │   ├── routes.dart        # 路由配置
│   │   ├── themes.dart        # 主题配置
│   │   └── constants.dart     # 常量
│   │
│   ├── core/                  # 核心功能
│   │   ├── network/           # 网络层
│   │   │   ├── api_client.dart
│   │   │   ├── api_endpoints.dart
│   │   │   └── interceptors.dart
│   │   ├── storage/           # 存储层
│   │   │   └── local_storage.dart
│   │   └── utils/             # 工具类
│   │       ├── validators.dart
│   │       └── formatters.dart
│   │
│   ├── data/                  # 数据层
│   │   ├── models/            # 数据模型
│   │   │   ├── user.dart
│   │   │   └── product.dart
│   │   └── repositories/      # 数据仓库
│   │       ├── user_repository.dart
│   │       └── product_repository.dart
│   │
│   ├── providers/             # 状态管理(Provider/GetX)
│   │   ├── auth_provider.dart
│   │   └── cart_provider.dart
│   │
│   ├── pages/                 # 页面
│   │   ├── auth/
│   │   │   ├── login_page.dart
│   │   │   └── register_page.dart
│   │   ├── home/
│   │   │   └── home_page.dart
│   │   └── profile/
│   │       └── profile_page.dart
│   │
│   └── widgets/               # 全局组件
│       ├── common/            # 通用组件
│       │   ├── loading_widget.dart
│       │   └── error_widget.dart
│       └── buttons/
│           └── primary_button.dart
│
├── assets/
├── test/
└── pubspec.yaml

Repository 模式示例

// lib/data/models/user.dart
class User {
  final int id;
  final String name;
  final String email;
  final String? avatar;

  User({
    required this.id,
    required this.name,
    required this.email,
    this.avatar,
  });

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'],
      name: json['name'],
      email: json['email'],
      avatar: json['avatar'],
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'name': name,
      'email': email,
      'avatar': avatar,
    };
  }
}
// lib/data/repositories/user_repository.dart
import '../models/user.dart';
import '../../core/network/api_client.dart';

class UserRepository {
  final ApiClient _apiClient;

  UserRepository(this._apiClient);

  // 获取用户信息
  Future<User> getUser(int id) async {
    final response = await _apiClient.get('/users/$id');
    return User.fromJson(response.data);
  }

  // 更新用户信息
  Future<User> updateUser(int id, Map<String, dynamic> data) async {
    final response = await _apiClient.put('/users/$id', data: data);
    return User.fromJson(response.data);
  }

  // 获取用户列表
  Future<List<User>> getUsers() async {
    final response = await _apiClient.get('/users');
    return (response.data as List)
        .map((json) => User.fromJson(json))
        .toList();
  }
}
// lib/providers/auth_provider.dart
import 'package:flutter/material.dart';
import '../data/models/user.dart';
import '../data/repositories/user_repository.dart';

class AuthProvider extends ChangeNotifier {
  final UserRepository _userRepository;
  
  User? _currentUser;
  bool _isLoading = false;
  String? _error;

  AuthProvider(this._userRepository);

  User? get currentUser => _currentUser;
  bool get isLoading => _isLoading;
  bool get isLoggedIn => _currentUser != null;
  String? get error => _error;

  Future<void> login(String email, String password) async {
    _isLoading = true;
    _error = null;
    notifyListeners();

    try {
      // 模拟登录逻辑
      _currentUser = await _userRepository.getUser(1);
    } catch (e) {
      _error = e.toString();
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  void logout() {
    _currentUser = null;
    notifyListeners();
  }
}

🏗️ 大型项目结构(功能模块划分)

适合团队协作的大型项目,按功能模块划分代码。

my_app/
├── lib/
│   ├── main.dart
│   ├── app.dart
│   │
│   ├── core/                      # 核心模块(全局共享)
│   │   ├── constants/
│   │   ├── theme/
│   │   ├── network/
│   │   ├── storage/
│   │   ├── utils/
│   │   └── widgets/               # 全局通用组件
│   │
│   ├── features/                  # 功能模块
│   │   │
│   │   ├── auth/                  # 认证模块
│   │   │   ├── data/
│   │   │   │   ├── models/
│   │   │   │   ├── repositories/
│   │   │   │   └── datasources/
│   │   │   ├── domain/
│   │   │   │   └── usecases/
│   │   │   └── presentation/
│   │   │       ├── pages/
│   │   │       ├── widgets/
│   │   │       └── providers/
│   │   │
│   │   ├── home/                  # 首页模块
│   │   │   ├── data/
│   │   │   ├── domain/
│   │   │   └── presentation/
│   │   │
│   │   ├── product/               # 商品模块
│   │   │   ├── data/
│   │   │   ├── domain/
│   │   │   └── presentation/
│   │   │
│   │   ├── cart/                  # 购物车模块
│   │   │   ├── data/
│   │   │   ├── domain/
│   │   │   └── presentation/
│   │   │
│   │   ├── order/                 # 订单模块
│   │   │   ├── data/
│   │   │   ├── domain/
│   │   │   └── presentation/
│   │   │
│   │   └── profile/               # 个人中心模块
│   │       ├── data/
│   │       ├── domain/
│   │       └── presentation/
│   │
│   └── shared/                    # 共享模块
│       ├── models/                # 共享数据模型
│       ├── widgets/               # 共享组件
│       └── services/              # 共享服务
│
├── assets/
├── test/
│   ├── unit/                      # 单元测试
│   ├── widget/                    # Widget 测试
│   └── integration/               # 集成测试
└── pubspec.yaml

功能模块示例

// lib/features/product/data/models/product.dart
class Product {
  final int id;
  final String name;
  final String description;
  final double price;
  final String imageUrl;
  final int stock;

  Product({
    required this.id,
    required this.name,
    required this.description,
    required this.price,
    required this.imageUrl,
    required this.stock,
  });

  factory Product.fromJson(Map<String, dynamic> json) {
    return Product(
      id: json['id'],
      name: json['name'],
      description: json['description'],
      price: (json['price'] as num).toDouble(),
      imageUrl: json['image_url'],
      stock: json['stock'],
    );
  }

  bool get isInStock => stock > 0;
}
// lib/features/product/data/repositories/product_repository.dart
import '../models/product.dart';
import '../../../../core/network/api_client.dart';

abstract class ProductRepository {
  Future<List<Product>> getProducts();
  Future<Product> getProductById(int id);
  Future<List<Product>> searchProducts(String query);
}

class ProductRepositoryImpl implements ProductRepository {
  final ApiClient _apiClient;

  ProductRepositoryImpl(this._apiClient);

  @override
  Future<List<Product>> getProducts() async {
    final response = await _apiClient.get('/products');
    return (response.data as List)
        .map((json) => Product.fromJson(json))
        .toList();
  }

  @override
  Future<Product> getProductById(int id) async {
    final response = await _apiClient.get('/products/$id');
    return Product.fromJson(response.data);
  }

  @override
  Future<List<Product>> searchProducts(String query) async {
    final response = await _apiClient.get('/products/search', 
      queryParameters: {'q': query},
    );
    return (response.data as List)
        .map((json) => Product.fromJson(json))
        .toList();
  }
}
// lib/features/product/presentation/providers/product_provider.dart
import 'package:flutter/material.dart';
import '../../data/models/product.dart';
import '../../data/repositories/product_repository.dart';

class ProductProvider extends ChangeNotifier {
  final ProductRepository _repository;

  ProductProvider(this._repository);

  List<Product> _products = [];
  Product? _selectedProduct;
  bool _isLoading = false;
  String? _error;

  List<Product> get products => _products;
  Product? get selectedProduct => _selectedProduct;
  bool get isLoading => _isLoading;
  String? get error => _error;

  Future<void> loadProducts() async {
    _isLoading = true;
    _error = null;
    notifyListeners();

    try {
      _products = await _repository.getProducts();
    } catch (e) {
      _error = '加载商品失败:$e';
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  Future<void> loadProductDetail(int id) async {
    _isLoading = true;
    _error = null;
    notifyListeners();

    try {
      _selectedProduct = await _repository.getProductById(id);
    } catch (e) {
      _error = '加载商品详情失败:$e';
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  Future<void> searchProducts(String query) async {
    if (query.isEmpty) {
      await loadProducts();
      return;
    }

    _isLoading = true;
    _error = null;
    notifyListeners();

    try {
      _products = await _repository.searchProducts(query);
    } catch (e) {
      _error = '搜索失败:$e';
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }
}
// lib/features/product/presentation/pages/product_list_page.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/product_provider.dart';
import '../widgets/product_card.dart';

class ProductListPage extends StatefulWidget {
  const ProductListPage({super.key});

  @override
  State<ProductListPage> createState() => _ProductListPageState();
}

class _ProductListPageState extends State<ProductListPage> {
  @override
  void initState() {
    super.initState();
    // 加载商品列表
    Future.microtask(() {
      context.read<ProductProvider>().loadProducts();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('商品列表')),
      body: Consumer<ProductProvider>(
        builder: (context, provider, child) {
          if (provider.isLoading) {
            return const Center(child: CircularProgressIndicator());
          }

          if (provider.error != null) {
            return Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(provider.error!),
                  const SizedBox(height: 16),
                  ElevatedButton(
                    onPressed: () => provider.loadProducts(),
                    child: const Text('重试'),
                  ),
                ],
              ),
            );
          }

          return GridView.builder(
            padding: const EdgeInsets.all(16),
            gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 2,
              childAspectRatio: 0.75,
              crossAxisSpacing: 16,
              mainAxisSpacing: 16,
            ),
            itemCount: provider.products.length,
            itemBuilder: (context, index) {
              return ProductCard(product: provider.products[index]);
            },
          );
        },
      ),
    );
  }
}

🏛️ 分层架构

MVC 模式

Model-View-Controller,适合简单项目。

lib/
├── models/          # Model - 数据模型
│   └── user.dart
├── views/           # View - 页面/UI
│   └── user_page.dart
├── controllers/     # Controller - 业务逻辑
│   └── user_controller.dart
└── main.dart
// models/user.dart
class User {
  final String name;
  final String email;
  
  User({required this.name, required this.email});
}

// controllers/user_controller.dart
class UserController {
  User? _user;
  
  User? get user => _user;
  
  Future<void> loadUser() async {
    // 加载用户数据
    _user = User(name: '张三', email: 'zhangsan@example.com');
  }
  
  void updateName(String name) {
    if (_user != null) {
      _user = User(name: name, email: _user!.email);
    }
  }
}

// views/user_page.dart
class UserPage extends StatefulWidget {
  @override
  State<UserPage> createState() => _UserPageState();
}

class _UserPageState extends State<UserPage> {
  final _controller = UserController();
  
  @override
  void initState() {
    super.initState();
    _loadData();
  }
  
  Future<void> _loadData() async {
    await _controller.loadUser();
    setState(() {});
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text(_controller.user?.name ?? '加载中...'),
      ),
    );
  }
}

MVVM 模式

Model-View-ViewModel,推荐使用 Provider/GetX。

lib/
├── models/          # Model - 数据模型
├── views/           # View - 页面/UI
├── viewmodels/      # ViewModel - 视图模型(状态+逻辑)
└── services/        # Services - 数据服务
// models/todo.dart
class Todo {
  final int id;
  final String title;
  final bool completed;
  
  Todo({
    required this.id,
    required this.title,
    this.completed = false,
  });
  
  Todo copyWith({String? title, bool? completed}) {
    return Todo(
      id: id,
      title: title ?? this.title,
      completed: completed ?? this.completed,
    );
  }
}

// services/todo_service.dart
class TodoService {
  Future<List<Todo>> fetchTodos() async {
    // 模拟 API 请求
    await Future.delayed(const Duration(seconds: 1));
    return [
      Todo(id: 1, title: '学习 Flutter'),
      Todo(id: 2, title: '写代码'),
      Todo(id: 3, title: '看文档'),
    ];
  }
}

// viewmodels/todo_viewmodel.dart
import 'package:flutter/material.dart';

class TodoViewModel extends ChangeNotifier {
  final TodoService _service;
  
  List<Todo> _todos = [];
  bool _isLoading = false;
  
  TodoViewModel(this._service);
  
  List<Todo> get todos => _todos;
  bool get isLoading => _isLoading;
  int get completedCount => _todos.where((t) => t.completed).length;
  
  Future<void> loadTodos() async {
    _isLoading = true;
    notifyListeners();
    
    _todos = await _service.fetchTodos();
    
    _isLoading = false;
    notifyListeners();
  }
  
  void toggleTodo(int id) {
    final index = _todos.indexWhere((t) => t.id == id);
    if (index != -1) {
      _todos[index] = _todos[index].copyWith(
        completed: !_todos[index].completed,
      );
      notifyListeners();
    }
  }
  
  void addTodo(String title) {
    final newTodo = Todo(
      id: DateTime.now().millisecondsSinceEpoch,
      title: title,
    );
    _todos.add(newTodo);
    notifyListeners();
  }
}

// views/todo_page.dart
class TodoPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_) => TodoViewModel(TodoService())..loadTodos(),
      child: const _TodoPageContent(),
    );
  }
}

class _TodoPageContent extends StatelessWidget {
  const _TodoPageContent();

  @override
  Widget build(BuildContext context) {
    final viewModel = context.watch<TodoViewModel>();
    
    return Scaffold(
      appBar: AppBar(
        title: Text('待办事项 (${viewModel.completedCount}/${viewModel.todos.length})'),
      ),
      body: viewModel.isLoading
          ? const Center(child: CircularProgressIndicator())
          : ListView.builder(
              itemCount: viewModel.todos.length,
              itemBuilder: (context, index) {
                final todo = viewModel.todos[index];
                return CheckboxListTile(
                  title: Text(
                    todo.title,
                    style: TextStyle(
                      decoration: todo.completed
                          ? TextDecoration.lineThrough
                          : null,
                    ),
                  ),
                  value: todo.completed,
                  onChanged: (_) => viewModel.toggleTodo(todo.id),
                );
              },
            ),
    );
  }
}

Clean Architecture(整洁架构)

适合复杂的大型项目,分层更清晰。

lib/
├── core/                 # 核心层(全局共享)
│   ├── error/           # 错误处理
│   ├── network/         # 网络配置
│   └── usecases/        # 基础 UseCase
│
├── features/
│   └── user/
│       ├── data/                    # 数据层
│       │   ├── datasources/        # 数据源
│       │   │   ├── user_remote_datasource.dart
│       │   │   └── user_local_datasource.dart
│       │   ├── models/             # 数据模型(DTO)
│       │   │   └── user_model.dart
│       │   └── repositories/       # 仓库实现
│       │       └── user_repository_impl.dart
│       │
│       ├── domain/                  # 领域层(业务逻辑)
│       │   ├── entities/           # 实体
│       │   │   └── user.dart
│       │   ├── repositories/       # 仓库接口
│       │   │   └── user_repository.dart
│       │   └── usecases/           # 用例
│       │       ├── get_user.dart
│       │       └── update_user.dart
│       │
│       └── presentation/            # 表示层
│           ├── pages/
│           ├── widgets/
│           └── bloc/               # 或 provider/cubit
│
└── injection_container.dart        # 依赖注入
// domain/entities/user.dart(实体 - 纯业务对象)
class User {
  final int id;
  final String name;
  final String email;

  const User({
    required this.id,
    required this.name,
    required this.email,
  });
}

// domain/repositories/user_repository.dart(仓库接口)
abstract class UserRepository {
  Future<User> getUser(int id);
  Future<void> updateUser(User user);
}

// domain/usecases/get_user.dart(用例 - 业务逻辑)
class GetUser {
  final UserRepository repository;

  GetUser(this.repository);

  Future<User> call(int id) async {
    return await repository.getUser(id);
  }
}

// data/models/user_model.dart(数据模型 - 带序列化)
class UserModel extends User {
  const UserModel({
    required super.id,
    required super.name,
    required super.email,
  });

  factory UserModel.fromJson(Map<String, dynamic> json) {
    return UserModel(
      id: json['id'],
      name: json['name'],
      email: json['email'],
    );
  }

  Map<String, dynamic> toJson() {
    return {'id': id, 'name': name, 'email': email};
  }
}

// data/datasources/user_remote_datasource.dart
abstract class UserRemoteDataSource {
  Future<UserModel> getUser(int id);
}

class UserRemoteDataSourceImpl implements UserRemoteDataSource {
  final ApiClient client;

  UserRemoteDataSourceImpl(this.client);

  @override
  Future<UserModel> getUser(int id) async {
    final response = await client.get('/users/$id');
    return UserModel.fromJson(response.data);
  }
}

// data/repositories/user_repository_impl.dart(仓库实现)
class UserRepositoryImpl implements UserRepository {
  final UserRemoteDataSource remoteDataSource;
  final UserLocalDataSource localDataSource;

  UserRepositoryImpl({
    required this.remoteDataSource,
    required this.localDataSource,
  });

  @override
  Future<User> getUser(int id) async {
    try {
      // 优先从网络获取
      final user = await remoteDataSource.getUser(id);
      // 缓存到本地
      await localDataSource.cacheUser(user);
      return user;
    } catch (e) {
      // 网络失败,从本地获取
      return await localDataSource.getUser(id);
    }
  }

  @override
  Future<void> updateUser(User user) async {
    // 实现更新逻辑
  }
}

📝 命名约定

文件命名

使用 小写字母 + 下划线 (snake_case):

✅ 正确:
user_profile_page.dart
api_service.dart
custom_button.dart

❌ 错误:
UserProfilePage.dart
apiService.dart
CustomButton.dart

类命名

使用 大驼峰 (PascalCase):

// ✅ 正确
class UserProfile {}
class ApiService {}
class CustomButton extends StatelessWidget {}

// ❌ 错误
class userProfile {}
class api_service {}

变量和函数命名

使用 小驼峰 (camelCase):

// ✅ 正确
String userName = 'Tom';
void loadUserData() {}
final isLoading = false;

// ❌ 错误
String user_name = 'Tom';
void LoadUserData() {}

常量命名

使用 小驼峰 或 全大写下划线:

// ✅ 两种风格都可以
const int maxRetryCount = 3;
const int MAX_RETRY_COUNT = 3;

const String apiBaseUrl = 'https://api.example.com';
const String API_BASE_URL = 'https://api.example.com';

私有成员

使用 下划线前缀:

class UserService {
  // 私有变量
  final String _apiKey;
  
  // 私有方法
  void _validateInput() {}
  
  // 公开方法
  Future<void> loadUser() async {}
}

📁 文件组织规范

导入顺序

按以下顺序组织 import 语句:

// 1. Dart SDK
import 'dart:async';
import 'dart:convert';

// 2. Flutter SDK
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

// 3. 第三方包
import 'package:dio/dio.dart';
import 'package:provider/provider.dart';

// 4. 项目内部包
import 'package:my_app/core/utils.dart';
import 'package:my_app/models/user.dart';

// 5. 相对路径导入
import '../widgets/custom_button.dart';
import './user_card.dart';

代码文件结构

// 1. 导入
import 'package:flutter/material.dart';

// 2. 常量
const double _kDefaultPadding = 16.0;

// 3. 枚举
enum UserStatus { active, inactive, pending }

// 4. 类定义
class UserPage extends StatefulWidget {
  // 4.1 静态常量
  static const routeName = '/user';
  
  // 4.2 成员变量
  final int userId;
  
  // 4.3 构造函数
  const UserPage({super.key, required this.userId});
  
  // 4.4 方法
  @override
  State<UserPage> createState() => _UserPageState();
}

class _UserPageState extends State<UserPage> {
  // 4.1 成员变量
  bool _isLoading = false;
  
  // 4.2 生命周期方法
  @override
  void initState() {
    super.initState();
    _loadData();
  }
  
  @override
  void dispose() {
    super.dispose();
  }
  
  // 4.3 私有方法
  Future<void> _loadData() async {}
  
  // 4.4 build 方法
  @override
  Widget build(BuildContext context) {
    return Scaffold();
  }
}

// 5. 辅助函数
String formatUserName(String name) => name.trim();

🎯 最佳实践总结

项目结构选择指南

项目规模推荐结构特点
小型(1-2人)简单分层快速开发,易于理解
中型(3-5人)功能模块 + Repository清晰分层,便于维护
大型(5人以上)Clean Architecture高度解耦,易于测试

通用原则

代码组织原则

  1. 单一职责 - 每个文件/类只做一件事
  2. 高内聚低耦合 - 相关代码放一起,减少依赖
  3. 统一命名 - 团队保持一致的命名风格
  4. 合理分层 - 业务逻辑和 UI 分离
  5. 便于测试 - 代码结构要方便写单元测试

避免常见错误

// ❌ 错误:把所有逻辑写在 UI 中
class BadPage extends StatefulWidget {
  @override
  Widget build(BuildContext context) {
    // 直接在这里调用 API、处理数据...
  }
}

// ✅ 正确:分离业务逻辑
class GoodPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<UserProvider>(
      builder: (context, provider, child) {
        // UI 只负责展示
      },
    );
  }
}

// ❌ 错误:超大文件(>500行)
// 一个文件包含多个类和大量逻辑

// ✅ 正确:拆分文件
// user_page.dart - 页面
// user_provider.dart - 状态管理
// user_widgets.dart - 子组件

💪 练习题

  1. 将一个简单的计数器应用重构为 MVC 模式
  2. 创建一个中型项目结构,包含用户模块和商品模块
  3. 为一个功能模块实现 Repository 模式
  4. 实践 Clean Architecture,实现一个简单的待办事项功能

🚀 下一步

了解了项目结构后,你可以前往 附录C - 国际化配置,学习如何让你的 App 支持多语言!


由 编程指南 提供

最近更新: 2026/2/3 16:24
Contributors: 王长安
Prev
附录A - UI 框架与组件库推荐
Next
附录C - 国际化配置