Flutter 组件通信完全指南

📚 目录

  • 什么是组件通信
  • [1. 父传子(Parent to Child)](#1. 父传子(Parent to Child))
  • [2. 子传父(Child to Parent)](#2. 子传父(Child to Parent))
  • [3. 兄弟组件通信](#3. 兄弟组件通信)
  • [4. 跨层级通信](#4. 跨层级通信)
  • [5. 全局状态管理](#5. 全局状态管理)
  • 实战案例
  • 最佳实践

什么是组件通信?

在 Flutter 中,组件(Widget)之间经常需要传递数据和事件。组件通信就是解决这个问题的方法。

常见的通信场景

复制代码
父组件
  ├── 子组件 A
  └── 子组件 B
  • 父传子:父组件向子组件传递数据
  • 子传父:子组件向父组件传递事件或数据
  • 兄弟通信:子组件 A 和子组件 B 之间通信
  • 跨层级:祖先组件和后代组件之间通信

1. 父传子(Parent to Child)

父传子是最简单的通信方式,通过构造函数参数传递数据。

基本原理

父组件创建子组件时,通过构造函数传递数据给子组件。

案例1:传递简单数据

dart 复制代码
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: ParentWidget(),
    );
  }
}

// 父组件
class ParentWidget extends StatelessWidget {
  const ParentWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 父组件的数据
    String userName = '张三';
    int userAge = 25;
    
    return Scaffold(
      appBar: AppBar(title: const Text('父传子 - 基础示例')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text(
              '父组件',
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 20),
            // 通过构造函数传递数据给子组件
            ChildWidget(
              name: userName,
              age: userAge,
            ),
          ],
        ),
      ),
    );
  }
}

// 子组件
class ChildWidget extends StatelessWidget {
  // 1. 定义接收的参数
  final String name;
  final int age;
  
  // 2. 在构造函数中接收参数
  const ChildWidget({
    Key? key,
    required this.name,  // required 表示必传
    required this.age,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        color: Colors.blue[100],
        borderRadius: BorderRadius.circular(10),
      ),
      child: Column(
        children: [
          const Text(
            '子组件',
            style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
          ),
          const SizedBox(height: 10),
          // 3. 使用接收到的数据
          Text('姓名: $name', style: const TextStyle(fontSize: 18)),
          Text('年龄: $age', style: const TextStyle(fontSize: 18)),
        ],
      ),
    );
  }
}

关键点:

  1. 子组件定义 final 属性接收数据
  2. 构造函数中使用 required 标记必传参数
  3. 父组件创建子组件时传递数据

案例2:传递复杂对象

dart 复制代码
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: UserListPage(),
    );
  }
}

// 用户数据模型
class User {
  final String name;
  final int age;
  final String avatar;
  
  User({
    required this.name,
    required this.age,
    required this.avatar,
  });
}

// 父组件
class UserListPage extends StatelessWidget {
  const UserListPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 父组件的数据
    final List<User> users = [
      User(name: '张三', age: 25, avatar: '👨'),
      User(name: '李四', age: 30, avatar: '👩'),
      User(name: '王五', age: 28, avatar: '👨‍💼'),
    ];
    
    return Scaffold(
      appBar: AppBar(title: const Text('父传子 - 传递对象')),
      body: ListView.builder(
        itemCount: users.length,
        itemBuilder: (context, index) {
          // 传递整个对象给子组件
          return UserCard(user: users[index]);
        },
      ),
    );
  }
}

// 子组件
class UserCard extends StatelessWidget {
  final User user;  // 接收 User 对象
  
  const UserCard({
    Key? key,
    required this.user,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.all(10),
      child: ListTile(
        leading: Text(
          user.avatar,
          style: const TextStyle(fontSize: 40),
        ),
        title: Text(user.name),
        subtitle: Text('年龄: ${user.age}'),
      ),
    );
  }
}

案例3:传递可选参数

dart 复制代码
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: OptionalParamsPage(),
    );
  }
}

class OptionalParamsPage extends StatelessWidget {
  const OptionalParamsPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('父传子 - 可选参数')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // 传递所有参数
            CustomButton(
              text: '完整按钮',
              color: Colors.blue,
              icon: Icons.check,
            ),
            const SizedBox(height: 20),
            // 只传递必需参数
            CustomButton(text: '简单按钮'),
          ],
        ),
      ),
    );
  }
}

class CustomButton extends StatelessWidget {
  final String text;           // 必需参数
  final Color? color;          // 可选参数
  final IconData? icon;        // 可选参数
  
  const CustomButton({
    Key? key,
    required this.text,        // 必需
    this.color,                // 可选
    this.icon,                 // 可选
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ElevatedButton.icon(
      onPressed: () {},
      icon: Icon(icon ?? Icons.touch_app),  // 使用默认值
      label: Text(text),
      style: ElevatedButton.styleFrom(
        backgroundColor: color ?? Colors.grey,  // 使用默认值
        padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
      ),
    );
  }
}

2. 子传父(Child to Parent)

子传父通过**回调函数(Callback)**实现,子组件触发事件时调用父组件传递的函数。

基本原理

  1. 父组件定义一个函数
  2. 将函数作为参数传递给子组件
  3. 子组件在需要时调用这个函数

案例1:基础回调

dart 复制代码
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: CallbackDemo(),
    );
  }
}

// 父组件
class CallbackDemo extends StatefulWidget {
  const CallbackDemo({Key? key}) : super(key: key);

  @override
  State<CallbackDemo> createState() => _CallbackDemoState();
}

class _CallbackDemoState extends State<CallbackDemo> {
  String message = '等待子组件发送消息...';

  // 1. 父组件定义回调函数
  void handleChildMessage(String msg) {
    setState(() {
      message = msg;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('子传父 - 基础回调')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              padding: const EdgeInsets.all(20),
              decoration: BoxDecoration(
                color: Colors.green[100],
                borderRadius: BorderRadius.circular(10),
              ),
              child: Column(
                children: [
                  const Text(
                    '父组件',
                    style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
                  ),
                  const SizedBox(height: 10),
                  Text(
                    '收到消息: $message',
                    style: const TextStyle(fontSize: 18),
                  ),
                ],
              ),
            ),
            const SizedBox(height: 40),
            // 2. 将回调函数传递给子组件
            ChildButton(onPressed: handleChildMessage),
          ],
        ),
      ),
    );
  }
}

// 子组件
class ChildButton extends StatelessWidget {
  // 3. 子组件接收回调函数
  final Function(String) onPressed;
  
  const ChildButton({
    Key? key,
    required this.onPressed,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        color: Colors.blue[100],
        borderRadius: BorderRadius.circular(10),
      ),
      child: Column(
        children: [
          const Text(
            '子组件',
            style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
          ),
          const SizedBox(height: 10),
          ElevatedButton(
            onPressed: () {
              // 4. 子组件调用回调函数,传递数据给父组件
              onPressed('你好,我是子组件!');
            },
            child: const Text('发送消息给父组件'),
          ),
        ],
      ),
    );
  }
}

关键点:

  1. 父组件定义回调函数 handleChildMessage
  2. 通过构造函数传递给子组件 onPressed: handleChildMessage
  3. 子组件接收函数类型参数 final Function(String) onPressed
  4. 子组件调用 onPressed('数据')

案例2:计数器示例(经典案例)

dart 复制代码
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: CounterPage(),
    );
  }
}

// 父组件
class CounterPage extends StatefulWidget {
  const CounterPage({Key? key}) : super(key: key);

  @override
  State<CounterPage> createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  int count = 0;

  // 增加计数
  void increment() {
    setState(() {
      count++;
    });
  }

  // 减少计数
  void decrement() {
    setState(() {
      count--;
    });
  }

  // 重置计数
  void reset() {
    setState(() {
      count = 0;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('子传父 - 计数器')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              padding: const EdgeInsets.all(30),
              decoration: BoxDecoration(
                color: Colors.blue[100],
                borderRadius: BorderRadius.circular(15),
              ),
              child: Column(
                children: [
                  const Text(
                    '父组件',
                    style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
                  ),
                  const SizedBox(height: 20),
                  Text(
                    '当前计数: $count',
                    style: const TextStyle(fontSize: 48, fontWeight: FontWeight.bold),
                  ),
                ],
              ),
            ),
            const SizedBox(height: 40),
            // 传递三个回调函数给子组件
            CounterButtons(
              onIncrement: increment,
              onDecrement: decrement,
              onReset: reset,
            ),
          ],
        ),
      ),
    );
  }
}

// 子组件
class CounterButtons extends StatelessWidget {
  final VoidCallback onIncrement;  // 无参数的回调
  final VoidCallback onDecrement;
  final VoidCallback onReset;
  
  const CounterButtons({
    Key? key,
    required this.onIncrement,
    required this.onDecrement,
    required this.onReset,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        color: Colors.green[100],
        borderRadius: BorderRadius.circular(15),
      ),
      child: Column(
        children: [
          const Text(
            '子组件',
            style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
          ),
          const SizedBox(height: 15),
          Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              ElevatedButton(
                onPressed: onDecrement,  // 调用父组件的函数
                style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
                child: const Icon(Icons.remove),
              ),
              const SizedBox(width: 10),
              ElevatedButton(
                onPressed: onReset,
                style: ElevatedButton.styleFrom(backgroundColor: Colors.orange),
                child: const Icon(Icons.refresh),
              ),
              const SizedBox(width: 10),
              ElevatedButton(
                onPressed: onIncrement,
                style: ElevatedButton.styleFrom(backgroundColor: Colors.green),
                child: const Icon(Icons.add),
              ),
            ],
          ),
        ],
      ),
    );
  }
}

VoidCallback 说明:

  • VoidCallback 是 Flutter 内置的类型,表示无参数无返回值的函数
  • 等同于 void Function()

案例3:表单提交(传递多个参数)

dart 复制代码
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: FormPage(),
    );
  }
}

// 父组件
class FormPage extends StatefulWidget {
  const FormPage({Key? key}) : super(key: key);

  @override
  State<FormPage> createState() => _FormPageState();
}

class _FormPageState extends State<FormPage> {
  String submittedData = '暂无提交数据';

  // 处理表单提交
  void handleSubmit(String name, String email) {
    setState(() {
      submittedData = '姓名: $name\n邮箱: $email';
    });
    
    // 显示提示
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('表单提交成功!')),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('子传父 - 表单提交')),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(20),
        child: Column(
          children: [
            Container(
              padding: const EdgeInsets.all(20),
              decoration: BoxDecoration(
                color: Colors.blue[100],
                borderRadius: BorderRadius.circular(10),
              ),
              child: Column(
                children: [
                  const Text(
                    '父组件 - 接收数据',
                    style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                  ),
                  const SizedBox(height: 10),
                  Text(
                    submittedData,
                    style: const TextStyle(fontSize: 16),
                  ),
                ],
              ),
            ),
            const SizedBox(height: 30),
            // 传递回调函数给表单组件
            UserForm(onSubmit: handleSubmit),
          ],
        ),
      ),
    );
  }
}

// 子组件 - 表单
class UserForm extends StatefulWidget {
  final Function(String name, String email) onSubmit;
  
  const UserForm({
    Key? key,
    required this.onSubmit,
  }) : super(key: key);

  @override
  State<UserForm> createState() => _UserFormState();
}

class _UserFormState extends State<UserForm> {
  final TextEditingController nameController = TextEditingController();
  final TextEditingController emailController = TextEditingController();

  @override
  void dispose() {
    nameController.dispose();
    emailController.dispose();
    super.dispose();
  }

  void submit() {
    String name = nameController.text;
    String email = emailController.text;
    
    if (name.isEmpty || email.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('请填写完整信息')),
      );
      return;
    }
    
    // 调用父组件的回调函数,传递多个参数
    widget.onSubmit(name, email);
    
    // 清空表单
    nameController.clear();
    emailController.clear();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        color: Colors.green[100],
        borderRadius: BorderRadius.circular(10),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const Text(
            '子组件 - 表单',
            style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
          ),
          const SizedBox(height: 15),
          TextField(
            controller: nameController,
            decoration: const InputDecoration(
              labelText: '姓名',
              border: OutlineInputBorder(),
              filled: true,
              fillColor: Colors.white,
            ),
          ),
          const SizedBox(height: 15),
          TextField(
            controller: emailController,
            decoration: const InputDecoration(
              labelText: '邮箱',
              border: OutlineInputBorder(),
              filled: true,
              fillColor: Colors.white,
            ),
          ),
          const SizedBox(height: 20),
          SizedBox(
            width: double.infinity,
            child: ElevatedButton(
              onPressed: submit,
              child: const Text('提交'),
            ),
          ),
        ],
      ),
    );
  }
}

3. 兄弟组件通信

兄弟组件之间不能直接通信,需要通过父组件作为中介

原理

复制代码
父组件(管理状态)
  ├── 子组件 A(触发事件)
  └── 子组件 B(接收数据)
  1. 子组件 A 通过回调通知父组件
  2. 父组件更新状态
  3. 子组件 B 通过 props 接收新数据

案例:兄弟组件通信

dart 复制代码
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: SiblingCommunicationPage(),
    );
  }
}

// 父组件 - 管理状态
class SiblingCommunicationPage extends StatefulWidget {
  const SiblingCommunicationPage({Key? key}) : super(key: key);

  @override
  State<SiblingCommunicationPage> createState() => _SiblingCommunicationPageState();
}

class _SiblingCommunicationPageState extends State<SiblingCommunicationPage> {
  String message = '暂无消息';
  Color selectedColor = Colors.blue;

  // 接收子组件 A 的消息
  void updateMessage(String msg) {
    setState(() {
      message = msg;
    });
  }

  // 接收子组件 A 的颜色选择
  void updateColor(Color color) {
    setState(() {
      selectedColor = color;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('兄弟组件通信')),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: Column(
          children: [
            Container(
              padding: const EdgeInsets.all(15),
              decoration: BoxDecoration(
                color: Colors.grey[200],
                borderRadius: BorderRadius.circular(10),
              ),
              child: const Text(
                '父组件(中介)',
                style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
              ),
            ),
            const SizedBox(height: 30),
            // 子组件 A - 发送消息
            SenderWidget(
              onSendMessage: updateMessage,
              onSelectColor: updateColor,
            ),
            const SizedBox(height: 30),
            // 子组件 B - 接收消息
            ReceiverWidget(
              message: message,
              color: selectedColor,
            ),
          ],
        ),
      ),
    );
  }
}

// 子组件 A - 发送者
class SenderWidget extends StatelessWidget {
  final Function(String) onSendMessage;
  final Function(Color) onSelectColor;
  
  const SenderWidget({
    Key? key,
    required this.onSendMessage,
    required this.onSelectColor,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        color: Colors.blue[100],
        borderRadius: BorderRadius.circular(10),
        border: Border.all(color: Colors.blue, width: 2),
      ),
      child: Column(
        children: [
          const Text(
            '子组件 A(发送者)',
            style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
          ),
          const SizedBox(height: 15),
          Wrap(
            spacing: 10,
            children: [
              ElevatedButton(
                onPressed: () => onSendMessage('你好!'),
                child: const Text('发送: 你好'),
              ),
              ElevatedButton(
                onPressed: () => onSendMessage('Flutter 很棒!'),
                child: const Text('发送: Flutter'),
              ),
            ],
          ),
          const SizedBox(height: 10),
          const Text('选择颜色:', style: TextStyle(fontWeight: FontWeight.bold)),
          const SizedBox(height: 10),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              _ColorButton(Colors.red, onSelectColor),
              _ColorButton(Colors.green, onSelectColor),
              _ColorButton(Colors.blue, onSelectColor),
              _ColorButton(Colors.orange, onSelectColor),
            ],
          ),
        ],
      ),
    );
  }
}

class _ColorButton extends StatelessWidget {
  final Color color;
  final Function(Color) onTap;
  
  const _ColorButton(this.color, this.onTap);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () => onTap(color),
      child: Container(
        width: 40,
        height: 40,
        margin: const EdgeInsets.symmetric(horizontal: 5),
        decoration: BoxDecoration(
          color: color,
          shape: BoxShape.circle,
          border: Border.all(color: Colors.white, width: 2),
        ),
      ),
    );
  }
}

// 子组件 B - 接收者
class ReceiverWidget extends StatelessWidget {
  final String message;
  final Color color;
  
  const ReceiverWidget({
    Key? key,
    required this.message,
    required this.color,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        color: color.withOpacity(0.2),
        borderRadius: BorderRadius.circular(10),
        border: Border.all(color: color, width: 2),
      ),
      child: Column(
        children: [
          const Text(
            '子组件 B(接收者)',
            style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
          ),
          const SizedBox(height: 15),
          Container(
            padding: const EdgeInsets.all(15),
            decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.circular(8),
            ),
            child: Column(
              children: [
                const Text(
                  '收到的消息:',
                  style: TextStyle(fontWeight: FontWeight.bold),
                ),
                const SizedBox(height: 10),
                Text(
                  message,
                  style: TextStyle(fontSize: 20, color: color),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

关键点:

  1. 父组件管理共享状态(message 和 color)
  2. 子组件 A 通过回调函数通知父组件
  3. 父组件更新状态后,子组件 B 自动接收新数据

4. 跨层级通信

当组件层级很深时,一层层传递数据很麻烦。Flutter 提供了 InheritedWidget 和更简单的方案。

方案1:使用 InheritedWidget

dart 复制代码
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: InheritedWidgetDemo(),
    );
  }
}

// 1. 创建 InheritedWidget
class UserData extends InheritedWidget {
  final String userName;
  final String userRole;
  
  const UserData({
    Key? key,
    required this.userName,
    required this.userRole,
    required Widget child,
  }) : super(key: key, child: child);

  // 提供静态方法供子组件获取数据
  static UserData? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<UserData>();
  }

  @override
  bool updateShouldNotify(UserData oldWidget) {
    return userName != oldWidget.userName || userRole != oldWidget.userRole;
  }
}

// 2. 在顶层包裹 InheritedWidget
class InheritedWidgetDemo extends StatelessWidget {
  const InheritedWidgetDemo({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return UserData(
      userName: '张三',
      userRole: '管理员',
      child: Scaffold(
        appBar: AppBar(title: const Text('跨层级通信 - InheritedWidget')),
        body: const Center(
          child: LevelOne(),
        ),
      ),
    );
  }
}

// 第一层组件
class LevelOne extends StatelessWidget {
  const LevelOne({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        color: Colors.blue[100],
        borderRadius: BorderRadius.circular(10),
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: const [
          Text('第一层组件', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
          SizedBox(height: 20),
          LevelTwo(),
        ],
      ),
    );
  }
}

// 第二层组件
class LevelTwo extends StatelessWidget {
  const LevelTwo({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        color: Colors.green[100],
        borderRadius: BorderRadius.circular(10),
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: const [
          Text('第二层组件', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
          SizedBox(height: 20),
          LevelThree(),
        ],
      ),
    );
  }
}

// 第三层组件 - 直接获取顶层数据
class LevelThree extends StatelessWidget {
  const LevelThree({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 3. 在任意层级获取数据
    final userData = UserData.of(context);
    
    return Container(
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        color: Colors.orange[100],
        borderRadius: BorderRadius.circular(10),
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          const Text(
            '第三层组件',
            style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
          ),
          const SizedBox(height: 10),
          Text('用户名: ${userData?.userName}'),
          Text('角色: ${userData?.userRole}'),
        ],
      ),
    );
  }
}

方案2:使用 Provider(推荐)

Provider 是 Flutter 官方推荐的状态管理方案,更简单易用。

首先在 pubspec.yaml 添加依赖:

yaml 复制代码
dependencies:
  flutter:
    sdk: flutter
  provider: ^6.0.0
dart 复制代码
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 1. 在顶层提供数据
    return ChangeNotifierProvider(
      create: (context) => CounterModel(),
      child: const MaterialApp(
        home: ProviderDemo(),
      ),
    );
  }
}

// 2. 创建数据模型
class CounterModel extends ChangeNotifier {
  int _count = 0;
  
  int get count => _count;
  
  void increment() {
    _count++;
    notifyListeners();  // 通知所有监听者
  }
  
  void decrement() {
    _count--;
    notifyListeners();
  }
}

class ProviderDemo extends StatelessWidget {
  const ProviderDemo({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('跨层级通信 - Provider')),
      body: const Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            DisplayWidget(),
            SizedBox(height: 30),
            ButtonWidget(),
          ],
        ),
      ),
    );
  }
}

// 显示组件 - 监听数据变化
class DisplayWidget extends StatelessWidget {
  const DisplayWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 3. 监听数据变化
    final counter = context.watch<CounterModel>();
    
    return Container(
      padding: const EdgeInsets.all(30),
      decoration: BoxDecoration(
        color: Colors.blue[100],
        borderRadius: BorderRadius.circular(15),
      ),
      child: Column(
        children: [
          const Text(
            '显示组件',
            style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
          ),
          const SizedBox(height: 15),
          Text(
            '${counter.count}',
            style: const TextStyle(fontSize: 48, fontWeight: FontWeight.bold),
          ),
        ],
      ),
    );
  }
}

// 按钮组件 - 修改数据
class ButtonWidget extends StatelessWidget {
  const ButtonWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 4. 获取数据但不监听变化
    final counter = context.read<CounterModel>();
    
    return Container(
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        color: Colors.green[100],
        borderRadius: BorderRadius.circular(15),
      ),
      child: Column(
        children: [
          const Text(
            '按钮组件',
            style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
          ),
          const SizedBox(height: 15),
          Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              ElevatedButton(
                onPressed: counter.decrement,
                child: const Icon(Icons.remove),
              ),
              const SizedBox(width: 20),
              ElevatedButton(
                onPressed: counter.increment,
                child: const Icon(Icons.add),
              ),
            ],
          ),
        ],
      ),
    );
  }
}

Provider 的三种获取方式:

  • context.watch<T>() - 监听变化,数据改变时重建
  • context.read<T>() - 只读取,不监听变化
  • context.select<T, R>() - 只监听特定属性

5. 全局状态管理

对于复杂应用,推荐使用专业的状态管理方案。

常见方案对比

方案 难度 适用场景
setState 单个组件内部状态
InheritedWidget ⭐⭐ 简单的跨层级通信
Provider ⭐⭐ 中小型应用(推荐)
Riverpod ⭐⭐⭐ 中大型应用
Bloc ⭐⭐⭐⭐ 大型应用,需要严格架构
GetX ⭐⭐ 快速开发

Provider 完整示例(购物车)

dart 复制代码
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => CartModel(),
      child: const MaterialApp(
        home: ShoppingPage(),
      ),
    );
  }
}

// 商品模型
class Product {
  final String name;
  final double price;
  
  Product(this.name, this.price);
}

// 购物车模型
class CartModel extends ChangeNotifier {
  final List<Product> _items = [];
  
  List<Product> get items => _items;
  
  int get itemCount => _items.length;
  
  double get totalPrice {
    return _items.fold(0, (sum, item) => sum + item.price);
  }
  
  void addItem(Product product) {
    _items.add(product);
    notifyListeners();
  }
  
  void removeItem(int index) {
    _items.removeAt(index);
    notifyListeners();
  }
  
  void clear() {
    _items.clear();
    notifyListeners();
  }
}

// 主页面
class ShoppingPage extends StatelessWidget {
  const ShoppingPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('全局状态管理 - 购物车'),
        actions: [
          // 购物车图标显示数量
          Consumer<CartModel>(
            builder: (context, cart, child) {
              return Stack(
                children: [
                  IconButton(
                    icon: const Icon(Icons.shopping_cart),
                    onPressed: () {
                      Navigator.push(
                        context,
                        MaterialPageRoute(
                          builder: (context) => const CartPage(),
                        ),
                      );
                    },
                  ),
                  if (cart.itemCount > 0)
                    Positioned(
                      right: 8,
                      top: 8,
                      child: Container(
                        padding: const EdgeInsets.all(4),
                        decoration: const BoxDecoration(
                          color: Colors.red,
                          shape: BoxShape.circle,
                        ),
                        child: Text(
                          '${cart.itemCount}',
                          style: const TextStyle(
                            color: Colors.white,
                            fontSize: 12,
                          ),
                        ),
                      ),
                    ),
                ],
              );
            },
          ),
        ],
      ),
      body: const ProductList(),
    );
  }
}

// 商品列表
class ProductList extends StatelessWidget {
  const ProductList({Key? key}) : super(key: key);

  final List<Product> products = const [
    Product('iPhone 15', 5999),
    Product('MacBook Pro', 12999),
    Product('iPad Air', 4599),
    Product('AirPods Pro', 1899),
    Product('Apple Watch', 2999),
  ];

  @override
  Widget build(BuildContext context) {
    final cart = context.read<CartModel>();
    
    return ListView.builder(
      itemCount: products.length,
      itemBuilder: (context, index) {
        final product = products[index];
        return Card(
          margin: const EdgeInsets.all(10),
          child: ListTile(
            title: Text(product.name),
            subtitle: Text('¥${product.price}'),
            trailing: ElevatedButton(
              onPressed: () {
                cart.addItem(product);
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(
                    content: Text('${product.name} 已加入购物车'),
                    duration: const Duration(seconds: 1),
                  ),
                );
              },
              child: const Text('加入购物车'),
            ),
          ),
        );
      },
    );
  }
}

// 购物车页面
class CartPage extends StatelessWidget {
  const CartPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('购物车'),
        actions: [
          IconButton(
            icon: const Icon(Icons.delete_outline),
            onPressed: () {
              context.read<CartModel>().clear();
            },
          ),
        ],
      ),
      body: Consumer<CartModel>(
        builder: (context, cart, child) {
          if (cart.itemCount == 0) {
            return const Center(
              child: Text('购物车是空的', style: TextStyle(fontSize: 18)),
            );
          }
          
          return Column(
            children: [
              Expanded(
                child: ListView.builder(
                  itemCount: cart.itemCount,
                  itemBuilder: (context, index) {
                    final product = cart.items[index];
                    return ListTile(
                      title: Text(product.name),
                      subtitle: Text('¥${product.price}'),
                      trailing: IconButton(
                        icon: const Icon(Icons.remove_circle_outline),
                        onPressed: () {
                          cart.removeItem(index);
                        },
                      ),
                    );
                  },
                ),
              ),
              Container(
                padding: const EdgeInsets.all(20),
                decoration: BoxDecoration(
                  color: Colors.grey[200],
                  boxShadow: [
                    BoxShadow(
                      color: Colors.grey.withOpacity(0.3),
                      spreadRadius: 2,
                      blurRadius: 5,
                    ),
                  ],
                ),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Text(
                      '总计: ¥${cart.totalPrice.toStringAsFixed(2)}',
                      style: const TextStyle(
                        fontSize: 20,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    ElevatedButton(
                      onPressed: () {
                        showDialog(
                          context: context,
                          builder: (context) => AlertDialog(
                            title: const Text('确认结算'),
                            content: Text('总金额: ¥${cart.totalPrice.toStringAsFixed(2)}'),
                            actions: [
                              TextButton(
                                onPressed: () => Navigator.pop(context),
                                child: const Text('取消'),
                              ),
                              TextButton(
                                onPressed: () {
                                  cart.clear();
                                  Navigator.pop(context);
                                  Navigator.pop(context);
                                },
                                child: const Text('确认'),
                              ),
                            ],
                          ),
                        );
                      },
                      child: const Text('结算'),
                    ),
                  ],
                ),
              ),
            ],
          );
        },
      ),
    );
  }
}

实战案例

综合案例:Todo 应用(包含所有通信方式)

dart 复制代码
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: TodoApp(),
    );
  }
}

// Todo 数据模型
class Todo {
  String title;
  bool isDone;
  
  Todo({required this.title, this.isDone = false});
}

// 主页面 - 管理所有状态
class TodoApp extends StatefulWidget {
  const TodoApp({Key? key}) : super(key: key);

  @override
  State<TodoApp> createState() => _TodoAppState();
}

class _TodoAppState extends State<TodoApp> {
  final List<Todo> todos = [];
  
  // 添加 Todo(子传父)
  void addTodo(String title) {
    setState(() {
      todos.add(Todo(title: title));
    });
  }
  
  // 切换完成状态(子传父)
  void toggleTodo(int index) {
    setState(() {
      todos[index].isDone = !todos[index].isDone;
    });
  }
  
  // 删除 Todo(子传父)
  void deleteTodo(int index) {
    setState(() {
      todos.removeAt(index);
    });
  }
  
  // 编辑 Todo(子传父)
  void editTodo(int index, String newTitle) {
    setState(() {
      todos[index].title = newTitle;
    });
  }

  @override
  Widget build(BuildContext context) {
    // 统计数据
    int totalCount = todos.length;
    int doneCount = todos.where((todo) => todo.isDone).length;
    int pendingCount = totalCount - doneCount;
    
    return Scaffold(
      appBar: AppBar(
        title: const Text('Todo 应用 - 综合案例'),
      ),
      body: Column(
        children: [
          // 统计组件(父传子)
          TodoStats(
            total: totalCount,
            done: doneCount,
            pending: pendingCount,
          ),
          const Divider(),
          // 输入组件(子传父)
          TodoInput(onAdd: addTodo),
          const Divider(),
          // 列表组件(父传子 + 子传父)
          Expanded(
            child: TodoList(
              todos: todos,
              onToggle: toggleTodo,
              onDelete: deleteTodo,
              onEdit: editTodo,
            ),
          ),
        ],
      ),
    );
  }
}

// 统计组件 - 接收数据(父传子)
class TodoStats extends StatelessWidget {
  final int total;
  final int done;
  final int pending;
  
  const TodoStats({
    Key? key,
    required this.total,
    required this.done,
    required this.pending,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(15),
      color: Colors.blue[50],
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: [
          _StatItem('总计', total, Colors.blue),
          _StatItem('已完成', done, Colors.green),
          _StatItem('待办', pending, Colors.orange),
        ],
      ),
    );
  }
}

class _StatItem extends StatelessWidget {
  final String label;
  final int count;
  final Color color;
  
  const _StatItem(this.label, this.count, this.color);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text(
          '$count',
          style: TextStyle(
            fontSize: 24,
            fontWeight: FontWeight.bold,
            color: color,
          ),
        ),
        Text(label, style: TextStyle(color: Colors.grey[600])),
      ],
    );
  }
}

// 输入组件 - 发送数据(子传父)
class TodoInput extends StatefulWidget {
  final Function(String) onAdd;
  
  const TodoInput({
    Key? key,
    required this.onAdd,
  }) : super(key: key);

  @override
  State<TodoInput> createState() => _TodoInputState();
}

class _TodoInputState extends State<TodoInput> {
  final TextEditingController controller = TextEditingController();

  void submit() {
    if (controller.text.trim().isEmpty) return;
    
    widget.onAdd(controller.text.trim());
    controller.clear();
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(15),
      child: Row(
        children: [
          Expanded(
            child: TextField(
              controller: controller,
              decoration: const InputDecoration(
                hintText: '输入待办事项...',
                border: OutlineInputBorder(),
              ),
              onSubmitted: (_) => submit(),
            ),
          ),
          const SizedBox(width: 10),
          ElevatedButton(
            onPressed: submit,
            child: const Text('添加'),
          ),
        ],
      ),
    );
  }
}

// 列表组件 - 接收数据和回调(父传子 + 子传父)
class TodoList extends StatelessWidget {
  final List<Todo> todos;
  final Function(int) onToggle;
  final Function(int) onDelete;
  final Function(int, String) onEdit;
  
  const TodoList({
    Key? key,
    required this.todos,
    required this.onToggle,
    required this.onDelete,
    required this.onEdit,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    if (todos.isEmpty) {
      return const Center(
        child: Text(
          '暂无待办事项\n点击上方添加按钮开始',
          textAlign: TextAlign.center,
          style: TextStyle(fontSize: 16, color: Colors.grey),
        ),
      );
    }
    
    return ListView.builder(
      itemCount: todos.length,
      itemBuilder: (context, index) {
        return TodoItem(
          todo: todos[index],
          onToggle: () => onToggle(index),
          onDelete: () => onDelete(index),
          onEdit: (newTitle) => onEdit(index, newTitle),
        );
      },
    );
  }
}

// Todo 项组件 - 接收数据和回调
class TodoItem extends StatelessWidget {
  final Todo todo;
  final VoidCallback onToggle;
  final VoidCallback onDelete;
  final Function(String) onEdit;
  
  const TodoItem({
    Key? key,
    required this.todo,
    required this.onToggle,
    required this.onDelete,
    required this.onEdit,
  }) : super(key: key);

  void showEditDialog(BuildContext context) {
    final controller = TextEditingController(text: todo.title);
    
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('编辑待办'),
        content: TextField(
          controller: controller,
          decoration: const InputDecoration(
            border: OutlineInputBorder(),
          ),
          autofocus: true,
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('取消'),
          ),
          TextButton(
            onPressed: () {
              if (controller.text.trim().isNotEmpty) {
                onEdit(controller.text.trim());
                Navigator.pop(context);
              }
            },
            child: const Text('保存'),
          ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.symmetric(horizontal: 15, vertical: 5),
      child: ListTile(
        leading: Checkbox(
          value: todo.isDone,
          onChanged: (_) => onToggle(),
        ),
        title: Text(
          todo.title,
          style: TextStyle(
            decoration: todo.isDone ? TextDecoration.lineThrough : null,
            color: todo.isDone ? Colors.grey : null,
          ),
        ),
        trailing: Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            IconButton(
              icon: const Icon(Icons.edit, color: Colors.blue),
              onPressed: () => showEditDialog(context),
            ),
            IconButton(
              icon: const Icon(Icons.delete, color: Colors.red),
              onPressed: onDelete,
            ),
          ],
        ),
      ),
    );
  }
}

最佳实践

1. 选择合适的通信方式

dart 复制代码
// ✅ 简单的父子通信 - 使用构造函数
class ChildWidget extends StatelessWidget {
  final String data;
  const ChildWidget({Key? key, required this.data}) : super(key: key);
  // ...
}

// ✅ 子传父 - 使用回调函数
class ChildWidget extends StatelessWidget {
  final VoidCallback onPressed;
  const ChildWidget({Key? key, required this.onPressed}) : super(key: key);
  // ...
}

// ✅ 跨层级通信 - 使用 Provider
class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final data = context.watch<MyModel>();
    // ...
  }
}

2. 回调函数命名规范

dart 复制代码
// ✅ 推荐:使用 on 前缀
final VoidCallback onPressed;
final Function(String) onChanged;
final Function(int) onItemSelected;

// ❌ 不推荐
final VoidCallback pressHandler;
final Function(String) changeFunc;

3. 避免过度传递

dart 复制代码
// ❌ 不推荐:层层传递
Parent -> Child1 -> Child2 -> Child3 (传递数据)

// ✅ 推荐:使用 Provider 或 InheritedWidget
Parent (提供数据)
  └── Child3 (直接获取数据)

4. 使用 const 优化性能

dart 复制代码
// ✅ 推荐:使用 const
const ChildWidget(data: 'hello')

// ❌ 不推荐:不使用 const
ChildWidget(data: 'hello')

5. 回调函数类型定义

dart 复制代码
// ✅ 推荐:使用 typedef 定义复杂回调
typedef OnItemSelected = void Function(int index, String value);

class MyWidget extends StatelessWidget {
  final OnItemSelected onItemSelected;
  // ...
}

// ✅ 推荐:使用内置类型
final VoidCallback onPressed;           // void Function()
final ValueChanged<String> onChanged;   // void Function(String)

6. 状态提升原则

dart 复制代码
// 状态应该放在需要它的最小公共父组件中

// ❌ 不推荐:状态放在顶层
App (state)
  └── PageA
      └── ComponentB (使用 state)

// ✅ 推荐:状态放在最近的父组件
App
  └── PageA (state)
      └── ComponentB (使用 state)

总结

通信方式速查表

场景 方式 示例
父传子 构造函数参数 ChildWidget(data: value)
子传父 回调函数 ChildWidget(onPressed: handlePress)
兄弟通信 通过父组件中转 父组件管理状态
跨层级 InheritedWidget MyData.of(context)
跨层级 Provider context.watch<MyModel>()
全局状态 Provider/Riverpod/Bloc 状态管理库

关键要点

  1. 父传子:通过构造函数传递数据

    dart 复制代码
    ChildWidget(name: 'value')
  2. 子传父:通过回调函数传递事件

    dart 复制代码
    ChildWidget(onPressed: () => handleEvent())
  3. 兄弟通信:通过父组件作为中介

    dart 复制代码
    父组件管理状态 → 子组件A触发 → 父组件更新 → 子组件B接收
  4. 跨层级:使用 InheritedWidget 或 Provider

    dart 复制代码
    context.watch<MyModel>()
  5. 全局状态:使用专业的状态管理方案

    • 小项目:Provider
    • 中大型:Riverpod 或 Bloc

选择建议

  • 简单应用:setState + 回调函数
  • 中型应用:Provider
  • 大型应用:Riverpod 或 Bloc
  • 快速开发:GetX

掌握这些通信方式,你就能轻松处理 Flutter 中的数据流动!🎉

相关推荐
奋斗的小青年!!2 小时前
Flutter开发OpenHarmony应用:设置页面组件的深度实践
flutter·harmonyos·鸿蒙
天天进步20152 小时前
从脚本到服务:5 分钟通过 Botasaurus 将你的爬虫逻辑转化为 Web API
前端·爬虫
大雷神2 小时前
HarmonyAPP 开发Flutter 嵌入鸿蒙原生 Swiper 组件教程
flutter·华为·harmonyos
沛沛老爹2 小时前
Web转AI架构篇:Agent Skills vs MCP-混合架构设计模式实战指南
java·前端·人工智能·架构·llm·rag
张张努力变强2 小时前
C++类和对象(一):inline函数、nullptr、类的定义深度解析
开发语言·前端·jvm·数据结构·c++·算法
Elcker3 小时前
JAVA-Web 项目研发中如何保持团队研发风格的统一
java·前端·javascript
时光慢煮3 小时前
基于 Flutter × OpenHarmony 的大小写转换工具实践
flutter·openharmony
selectDele3 小时前
Solid.js和React的比较
前端·javascript·react.js·solid.js
摘星编程3 小时前
React Native for OpenHarmony 实战:I18n 国际化详解
javascript·react native·react.js