第一个应用
从零开始,手把手构建一个简单的 Flutter 计数器应用。
创建项目
bash
flutter create counter_app
cd counter_app编写代码
打开 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(),
);
}
}
class CounterPage extends StatefulWidget {
const CounterPage({super.key});
@override
State<CounterPage> createState() => _CounterPageState();
}
class _CounterPageState extends State<CounterPage> {
int _counter = 0;
void _increment() {
setState(() {
_counter++;
});
}
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代码解读
应用结构
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 更新添加交互增强
在 body 的 Column.children 中追加一个重置按钮:
dart
TextButton(
onPressed: _counter == 0 ? null : _reset,
child: const Text('重置'),
),