1.带参数的回调示例
①先定义一个餐馆类
Dart
class Restaurant {
// 点餐方法,需要传入一个字符串和一个回调函数,onDelivered是形参,形参名称可以叫任何名字
//形参名(onDelivered)是给方法内部用的,实参名(message)是给调用者用的,它们不需要相同,只要类型匹配就行
void order(String food, Function(String) onDelivered) {
print("🍔 您点了:$food");
print("👨🍳 厨房正在制作...");
// 模拟制作时间(2秒)
Future.delayed(Duration(seconds: 2), () {
print("✅ 外卖已做好!");
// 调用回调函数,通知顾客
onDelivered("您的$food已送达,请用餐!");
});
}
}
②创建一个餐馆类的实例
Dart
var restaurant = Restaurant();
③点餐
方式1:匿名回调-直接写在参数里
Dart
// 点外卖,并留下"电话号码"(回调函数)
restaurant.order("汉堡",(message) {
// message是实参,实参名称也可以叫任何名字
print("📞 收到通知:$message");
print("🍽️ 开吃啦!");
});
print("🎉 点餐完成,等待外卖...");
}
// 执行流程:
// 1. 实参 (message) {...} 被传递给形参 onDelivered
// 2. 方法内部调用 onDelivered("消息")
// 3. 实际执行的是 (message) {...} 里面的代码
// 4. "消息" 被传递给了 message 参数
方式2:命名函数-先定义,再传入(更清晰的写法)
Dart
// 先定义一个回调函数
void myCallback(String message) {
print("📞 收到通知:$message");
print("🍽️ 开吃啦!");
}
// 调用时,把函数名传进去
restaurant.order("汉堡", myCallback);
// ↑
// 传的是函数名,不是调用
方式3:变量传递-用变量存储回调
Dart
// 把回调函数存在变量里
Function(String) myCallback = (message) {
print("📞 收到通知:$message");
print("🍽️ 开吃啦!");
};
// 把变量传进去
restaurant.order("汉堡", myCallback);
运行结果

详细的流程图
Dart
时间线 →
─────────────────────────────────────────────────────────────
[0秒] 创建餐厅对象
│
▼
调用 order("汉堡", 回调函数)
│
▼
进入 order 方法
│
▼
打印 "🍔 您点了:汉堡"
│
▼
打印 "👨🍳 厨房正在制作..."
│
▼
注册定时器(2秒后执行)
│
▼
order 方法结束
│
▼
打印 "🎉 点餐完成,等待外卖..."
│
▼
main 方法结束
【此时同步代码全部执行完毕,控制台已有3行输出】
═══════════════════════════════════════════════════════════════
[2秒后] 定时器触发
│
▼
打印 "✅ 外卖已做好!"
│
▼
onDelivered("您的汉堡已送达")
│ ↓
│ 执行之前传入的回调函数
│ ↓
│ 行16: 进入回调函数,message = "您的汉堡已送达"
│ ↓
│ 行17: 打印 "📞 收到通知:您的汉堡已送达"
│ ↓
│ 行18: 打印 "🍽️ 开吃啦!"
│ ↓
│ 行19: 回调结束
│
▼
定时器回调结束
逻辑图

参数传递过程

2.定义函数类型的回调
①定义餐馆类
Dart
// 1. 定义函数类型
typedef OnOrderDelivered = void Function(String message);
typedef OnOrderFailed = void Function(String error, int code);
// 2. 使用定义好的类型
class Restaurant {
void order(
String food,
OnOrderDelivered onSuccess, // 使用 typedef
OnOrderFailed onFailed, // 使用 typedef
) {
print("🍔 您点了:$food");
// 模拟订单处理
bool hasFood = true;
if (hasFood) {
Future.delayed(Duration(seconds: 2), () {
onSuccess("您的$food已送达!"); // 调用成功回调
});
} else {
onFailed("食材不足", 404); // 调用失败回调
}
}
}
②创建一个餐馆类的实例,并且点餐
Dart
var restaurant = Restaurant();
// 使用定义好的回调类型
restaurant.order(
"汉堡",
(message) {
print("✅ $message");
print("🍽️ 开吃啦!");
},
(error, code) {
print("❌ 错误 [$code]: $error");
print("😭 点餐失败");
},
);
运行结果
Dart
I/flutter (29269): 🍔 您点了:汉堡
I/flutter (29269): ✅ 您的汉堡已送达!
I/flutter (29269): 🍽️ 开吃啦!
3.可选回调的示例
①定义登录类
Dart
class AuthService {
void login({
required String username,
required String password,
Function()? onStart, // 开始登录时回调
Function(Map<String, dynamic> user)? onSuccess, // 成功时回调
Function(String error)? onFailed, // 失败时回调
Function()? onComplete, // 无论成功失败都回调
}) {
// 调用开始回调(如果有)
onStart?.call();
print("🔐 正在登录:$username");
// 模拟网络请求
Future.delayed(Duration(seconds: 2), () {
if (username == "admin" && password == "123456") {
// 登录成功,创建user对象
Map<String, dynamic> user = {
"id": 1,
"name": "管理员",
"email": "admin@example.com",
"token": "abc123xyz",
};
// 调用成功回调(如果有)
onSuccess?.call(user); //把user传回去
} else {
// 登录失败
// 调用失败回调(如果有)
onFailed?.call("用户名或密码错误");//把字符串传回去
}
// 无论如何都调用完成回调(如果有)
onComplete?.call();
});
}
}
②调用这个函数
Dart
var auth = AuthService();
print("===== 场景1:完整处理所有情况 =====");
auth.login(
username: "admin",
password: "123456",
onStart: () {
print("⏳ 开始登录流程...");
},
onSuccess: (user) { //拿到user
print("✅ 登录成功!");
print(" 欢迎:${user['name']}");
print(" Token:${user['token']}");
},
onFailed: (error) { //拿到字符串
print("❌ 登录失败:$error");
},
onComplete: () {
print("🏁 登录流程结束");
},
);
Future.delayed(Duration(seconds: 3), () {
print("\n===== 场景2:只关心成功 =====");
auth.login(
username: "admin",
password: "123456",
onSuccess: (user) {
print("🎉 欢迎回来,${user['name']}!");
},
// 不关心开始、失败、完成
);
});
Future.delayed(Duration(seconds: 6), () {
print("\n===== 场景3:只处理失败 =====");
auth.login(
username: "wrong",
password: "wrong",
onFailed: (error) {
print("⚠️ 登录失败:$error");
print("请检查用户名和密码");
},
// 只关心失败情况
);
});
运行结果
Dart
I/flutter ( 6011): ===== 场景1:完整处理所有情况 =====
I/flutter ( 6011): ⏳ 开始登录流程...
I/flutter ( 6011): 🔐 正在登录:admin
I/flutter ( 6011): ✅ 登录成功!
I/flutter ( 6011): 欢迎:管理员
I/flutter ( 6011): Token:abc123xyz
I/flutter ( 6011): 🏁 登录流程结束
I/flutter ( 6011): ===== 场景2:只关心成功 =====
I/flutter ( 6011): 🔐 正在登录:admin
I/flutter ( 6011): 🎉 欢迎回来,管理员!
I/flutter ( 6011): ===== 场景3:只处理失败 =====
I/flutter ( 6011): 🔐 正在登录:wrong
I/flutter ( 6011): ! 登录失败:用户名或密码错误
I/flutter ( 6011): 请检查用户名和密码
注意事项

4.UI组件回调
数据向下,事件向上:父组件通过参数传数据给子组件,子组件通过回调传事件给父组件
①自定义按钮组件
Dart
class MyButton extends StatelessWidget {
final String text;
final Color color;
final VoidCallback? onPressed; // 回调:无参数
const MyButton({
Key? key, //通过 key 定位 Widget,key是可选参数,静态布局不需要key
required this.text,
this.color = Colors.blue,
this.onPressed,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: color, //颜色
padding: EdgeInsets.symmetric(horizontal: 30, vertical: 15),
),
onPressed: onPressed, // 把回调传给 Flutter 的按钮
child: Text(
text, //文字
style: TextStyle(fontSize: 18),
),
);
}
}
②调用这个按钮类
Dart
return Scaffold(
appBar: AppBar(title: Text("自定义按钮")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 按钮1:带回调
MyButton(
text: "点击我",
color: Colors.green,
onPressed: () {
print("绿色按钮被点击了");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("你点击了绿色按钮!")),
);
},
),
SizedBox(height: 20),
// 按钮2:不带回调(禁用状态)
MyButton(
text: "禁用按钮",
color: Colors.grey,
onPressed: null, // null 表示禁用
),
],
),
),
);
5.数组传递回调
①构建多选列表组件类
Dart
/// 多选列表组件
class MultiSelectList extends StatefulWidget {
final List<String> items; // 所有选项
final Function(List<String>)? onSelectionChanged; // 回调:返回选中的数组
const MultiSelectList({
Key? key,
required this.items,
this.onSelectionChanged,
}) : super(key: key);
@override
_MultiSelectListState createState() => _MultiSelectListState();
}
class _MultiSelectListState extends State<MultiSelectList> {
List<String> _selectedItems = []; //存储用户选中的子项
//切换选中状态
void _toggleSelection(String item) {
setState(() {
if (_selectedItems.contains(item)) {
_selectedItems.remove(item);
} else {
_selectedItems.add(item);
}
// ***回调:传递选中的数组
widget.onSelectionChanged?.call(_selectedItems); //.call()是调用函数对象的标准方法
});
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: widget.items.length, //列表项数量
itemBuilder: (context, index) { //构建每一项
String item = widget.items[index]; //获取当前项
bool isSelected = _selectedItems.contains(item);//判断是否选中
return ListTile(
// 用户点击了"香蕉"旁边的复选框
// Flutter 自动调用这个复选框的 onChanged 回调
leading: Checkbox(
value: isSelected, //当前是否选中
onChanged: (_) => _toggleSelection(item), //状态改变时的回调
),
title: Text(item),
trailing: isSelected ? Icon(Icons.check, color: Colors.green) : null,
);
},
);
}
}
②调用这个类
Dart
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<StatefulWidget> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<String> _allItems = [
'苹果', '香蕉', '橙子', '葡萄', '西瓜', '芒果'
];
List<String> _selectedItems = [];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('多选列表'),
actions: [
if (_selectedItems.isNotEmpty)
TextButton(
onPressed: () {
_showSelectedDialog();
},
child: Text(
'确定 (${_selectedItems.length})',
style: TextStyle(color: Colors.blue),
),
),
],
),
body: Column(
children: [
// 显示已选中的数量
Container(
padding: EdgeInsets.all(16),
color: Colors.blue[50],
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'已选中 ${_selectedItems.length} 项',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
if (_selectedItems.isNotEmpty)
TextButton(
onPressed: () {
setState(() {
_selectedItems.clear();
});
},
child: Text('清空'),
),
],
),
),
// 多选列表
Expanded(
child: MultiSelectList( //引用外部类
items: _allItems, //传入原始数据
onSelectionChanged: (selected) { //传入回调函数
setState(() {
_selectedItems = selected; //把传回来的选中数组,更新UI的状态
});
print('选中的水果: $selected');
},
),
),
],
),
);
}
//展示选中了的列表项
void _showSelectedDialog() {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('选中的水果'),
content: Container(
width: double.maxFinite,
child: ListView.builder( //构建列表
shrinkWrap: true,
itemCount: _selectedItems.length, //列表长度
itemBuilder: (context, index) { //列表子项
return ListTile(
leading: Icon(Icons.check_circle, color: Colors.green),
title: Text(_selectedItems[index]),
);
},
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text('关闭'),
),
],
),
);
}
}
具体逻辑
Dart
HomePage 调用 MultiSelectList,传入原始数据
MultiSelectList 内部处理用户的选择
用户每次点击复选框,MultiSelectList 通过回调把选中的列表项传回给 HomePage
6.Future与回调
7.stream与回调