第一个应用
从零开始,手把手构建一个简单的 Flutter 计数器应用。
创建项目
bash
flutter create counter_app
cd counter_app项目结构
创建完成后,项目结构如下:
counter_app/
├── lib/ # ⭐ Dart 源码(你 90% 的时间都在这里)
│ └── main.dart # 应用入口
├── pubspec.yaml # ⭐ 项目配置(依赖、资源、元数据)
├── analysis_options.yaml # 代码规范配置
├── test/ # 测试文件
├── android/ # Android 原生工程(很少直接改)
├── ios/ # iOS 原生工程(很少直接改)
├── web/ # Web 平台文件
├── ohos/ # 鸿蒙平台文件(需 flutter-ohos 定制版)
└── README.md初学者关注点
- 现在就搞懂:
lib/、pubspec.yaml、main.dart - 用到再看:
android/、ios/等原生目录(需要写插件或改原生配置时才动) - 暂时忽略:
test/(先学会写功能,再学测试)
三个核心文件
1. pubspec.yaml — 项目配置
这是 Flutter 项目的"身份证",定义了项目是谁、依赖什么、包含哪些资源。
yaml
name: my_app # 包名(唯一标识)
description: My Flutter App # 描述
version: 1.0.0+1 # 版本号+构建号(1.0.0 是版本,1 是构建号)
environment:
sdk: ^3.6.0 # Dart SDK 版本约束
dependencies: # 运行时依赖(打包进 APP 的包)
flutter:
sdk: flutter
cupertino_icons: ^1.0.8 # iOS 风格图标
http: ^1.2.0 # 第三方包示例
dev_dependencies: # 开发依赖(只在开发时用,不打包进 APP)
flutter_test:
sdk: flutter
flutter_lints: ^5.0.0
flutter: # Flutter 专属配置
uses-material-design: true # 使用 Material 图标
assets: # 声明静态资源(必须声明才能使用)
- images/
- assets/data.json
fonts: # 自定义字体
- family: MyFont
fonts:
- asset: fonts/MyFont-Regular.ttf
- asset: fonts/MyFont-Bold.ttf
weight: 700常用操作:
| 操作 | 命令 |
|---|---|
| 安装/更新依赖 | flutter pub get |
| 添加第三方包 | flutter pub add http |
| 移除第三方包 | flutter pub remove http |
| 查看过期依赖 | flutter pub outdated |
| 升级依赖 | flutter pub upgrade |
注意
每次修改 pubspec.yaml 后,必须运行 flutter pub get 安装依赖,否则 IDE 会报错。
2. main.dart — 应用入口
Flutter 应用的启动文件,main() 函数是程序执行的起点:
dart
import 'package:flutter/material.dart';
void main() {
// ─── ★ runApp 启动应用 ──────────────
runApp(const MyApp());
// ─── ☆ runApp 启动应用 ──────────────
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
// ─── ★ MaterialApp 应用外壳 ──────────────
return MaterialApp(
title: 'My App',
home: Scaffold( // 页面骨架(提供 AppBar、Body 等)
appBar: AppBar(title: const Text('首页')),
body: const Center(child: Text('Hello Flutter!')),
),
);
// ─── ☆ MaterialApp 应用外壳 ──────────────
}
}关键理解:
| 概念 | 说明 |
|---|---|
main() | 程序入口,调用 runApp() 启动应用 |
runApp() | 接收一个 Widget 作为根组件,挂载到屏幕 |
MaterialApp | Material Design 风格的应用外壳,配置主题、路由等 |
Scaffold | 页面骨架,提供 AppBar、Body、FloatingActionButton 等区域 |
3. analysis_options.yaml — 代码规范
Dart 的静态代码分析配置,相当于"拼写检查器"——在你写代码时实时提示问题。
yaml
# 引入 Flutter 官方推荐规则集
include: package:flutter_lints/flutter.yaml
# 自定义规则
linter:
rules:
prefer_const_constructors: true # 优先用 const 构造函数
prefer_single_quotes: true # 优先用单引号
avoid_print: true # 避免用 print
# 排除不需要分析的文件
analyzer:
exclude:
- "**/*.g.dart" # 代码生成的文件
- "**/*.freezed.dart"
# 第三方 lint 插件(如使用 Riverpod 时添加)
# plugins:
# riverpod_lint: 3.1.3验证是否生效:
bash
flutter analyze # 扫描整个项目,报告所有问题IDE 会自动读取此文件,在编写代码时实时标黄/标红提示问题。修改配置后如果未生效,运行 flutter pub get 或重启 IDE。
lib/ 目录 — 你的主战场
lib/ 是你编写 Dart 代码的地方。项目初期只有一个 main.dart,随着功能增长需要合理组织:
lib/
├── main.dart # 入口:只做初始化和启动
├── app.dart # 根 Widget(MaterialApp)
├── pages/ # 页面
│ ├── home_page.dart
│ └── login_page.dart
├── widgets/ # 可复用组件
│ └── loading.dart
├── models/ # 数据模型
│ └── user.dart
├── services/ # 服务(网络请求、本地存储等)
│ └── api_service.dart
└── utils/ # 工具函数
└── validators.dart组织原则
- 入口简洁:
main.dart只负责启动,不超过 20 行 - 按功能分层:页面、组件、模型、服务各归其位
- 适度拆分:至少 2-3 处复用时才提取公共组件,避免过度封装
编写代码
打开 lib/main.dart,替换为以下内容:
dart
import 'package:flutter/material.dart';
void main() {
runApp(const CounterApp());
}
class CounterApp extends StatelessWidget {
const CounterApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '计数器',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorSchemeSeed: Colors.blue,
useMaterial3: true,
),
home: const CounterPage(),
);
}
}
// ─── ★ StatefulWidget 可变组件 ──────────────
class CounterPage extends StatefulWidget {
const CounterPage({super.key});
@override
State<CounterPage> createState() => _CounterPageState();
}
// ─── ☆ StatefulWidget 可变组件 ──────────────
class _CounterPageState extends State<CounterPage> {
// ─── ★ 可变状态变量 ──────────────
int _counter = 0;
// ─── ☆ 可变状态变量 ──────────────
void _increment() {
// ─── ★ setState 触发 UI 重建 ──────────────
setState(() {
_counter++;
});
// ─── ☆ setState 触发 UI 重建 ──────────────
}
void _decrement() {
setState(() {
_counter--;
});
}
void _reset() {
setState(() {
_counter = 0;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter 计数器'),
centerTitle: true,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'当前计数',
style: TextStyle(fontSize: 20, color: Colors.grey),
),
const SizedBox(height: 8),
Text(
'$_counter',
style: Theme.of(context).textTheme.displayLarge?.copyWith(
color: _counter > 0
? Colors.green
: _counter < 0
? Colors.red
: Colors.grey,
),
),
],
),
),
floatingActionButton: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
FloatingActionButton(
heroTag: 'add',
onPressed: _increment,
child: const Icon(Icons.add),
),
const SizedBox(height: 10),
FloatingActionButton(
heroTag: 'sub',
onPressed: _decrement,
child: const Icon(Icons.remove),
),
const SizedBox(height: 10),
FloatingActionButton.small(
heroTag: 'reset',
onPressed: _reset,
child: const Icon(Icons.refresh),
),
],
),
);
}
}运行项目
bash
# 确保设备已连接或模拟器已启动
flutter devices
# 运行
flutter run热重载 vs 热重启
| 操作 | 快捷键 | 说明 |
|---|---|---|
| 热重载 | r | 秒级生效,保持状态,修改 UI 时使用 |
| 热重启 | R | 完全重启,状态重置,修改初始化逻辑时使用 |
| 退出运行 | q | 停止应用 |
代码解读
应用结构
CounterApp (StatelessWidget)
└── MaterialApp
└── CounterPage (StatefulWidget)
└── Scaffold
├── AppBar ← 顶部导航栏
├── Center ← 内容区域(居中)
│ └── Column ← 垂直排列的列
│ ├── Text ← "当前计数"
│ └── Text ← 计数值
└── FloatingActionButton ← 悬浮按钮关键概念
| 概念 | 说明 |
|---|---|
StatelessWidget | 不可变组件,CounterApp 本身不需要状态 |
StatefulWidget | 可变组件,CounterPage 管理计数状态 |
setState() | 通知框架状态已变更,触发 UI 重建 |
Scaffold | Material Design 页面骨架,提供 AppBar、Body、FAB 等 |
build() | 描述 UI 的方法,每次状态变更都会重新调用 |
Theme.of(context) | 获取当前主题,实现样式复用 |
状态变化流程
用户点击 → _increment() → setState() → build() 重新执行 → UI 更新常用命令速查
flutter create — 创建项目
bash
flutter create <项目目录>常用参数:
| 参数 | 说明 |
|---|---|
--project-name <名称> | 指定项目名称(pubspec.yaml 中的 name),必须全小写,可用下划线分隔。若不指定则默认使用目录名 |
--platforms <平台列表> | 指定支持的平台,逗号分隔。可选:android、ios、web、ohos、macos、windows、linux |
--org <组织标识> | 指定组织标识(反向域名格式),用于生成包名。如 --org com.example,则包名为 com.example.<项目名> |
-t <模板> | 项目模板类型:app(默认)、module(模块)、plugin(插件)、plugin_ffi(FFI 插件) |
常见示例:
bash
# 指定项目名称和支持平台
flutter create --project-name hongmeng --platforms android,ios,web,ohos hongmeng--project-name hongmeng:项目名设为hongmeng--platforms android,ios,web,ohos:生成 Android、iOS、Web、鸿蒙四个平台目录- 最后的
hongmeng:创建hongmeng/目录
bash
# 指定组织标识,自定义包名
flutter create --platforms android,ios,ohos,web --org com.mawanli learn--org com.mawanli:包名变为com.mawanli.learnlearn:项目目录名,同时作为默认项目名
bash
# 在当前目录创建项目(适合已有空目录)
flutter create --platforms android,ios,ohos,web --org com.mawanli --project-name learn .--project-name learn:显式指定项目名(覆盖从目录名推断的默认值).:在当前目录创建,不新建子目录
flutter run — 运行项目
bash
flutter run # 在默认设备运行
flutter run -d <设备ID> # 在指定设备运行常用参数:
| 参数 | 说明 |
|---|---|
-d <设备ID> | 指定目标设备。常用值:chrome、web-server、ohos、设备序列号。通过 flutter devices 查看可用设备 |
--web-port <端口> | Web 服务器监听端口,仅 -d web-server 或 -d chrome 时有效,默认随机分配 |
--web-hostname <主机名> | Web 服务器监听主机名,默认 localhost(仅本机访问)。设为 0.0.0.0 允许局域网访问 |
常见示例:
bash
# Web 服务器模式运行,指定端口
flutter run -d web-server --web-port=8080-d web-server:不自动打开浏览器,终端输出访问 URL,适合远程开发环境--web-port=8080:访问地址为http://localhost:8080
bash
# 允许局域网访问的 Web 运行
flutter run -d web-server --web-hostname=0.0.0.0 --web-port=8080--web-hostname=0.0.0.0:监听所有网络接口,局域网设备可通过http://<本机IP>:8080访问- 适合在手机上预览 Web 版效果
web-server vs chrome
-d web-server:不自动打开浏览器,适合远程开发、CI/CD-d chrome:自动打开 Chrome 并支持 DevTools 调试,适合日常开发
其他日常命令
| 命令 | 说明 |
|---|---|
flutter devices | 查看可用设备 |
r | 热重载(运行中按,秒级生效) |
R | 热重启(运行中按,完全重启) |
q | 退出运行 |
依赖管理
| 命令 | 说明 |
|---|---|
flutter pub get | 安装依赖 |
flutter pub add 包名 | 添加依赖包 |
flutter pub remove 包名 | 移除依赖包 |
flutter pub outdated | 查看过期依赖 |
flutter pub upgrade | 升级依赖 |
构建与检查
| 命令 | 说明 |
|---|---|
flutter build apk | 构建 Android APK |
flutter build ios | 构建 iOS(需 macOS) |
flutter build web | 构建 Web |
flutter build ohos | 构建鸿蒙应用(需 flutter-ohos 定制版) |
flutter clean | 清理构建产物 |
flutter analyze | 静态代码分析 |
flutter test | 运行测试 |
