在这里插入图片描述

父组件向子组件传值

父传子是最基础的传值方式,核心是子组件定义接收参数的变量,父组件在创建子组件时传入数据。
实现步骤

  • 子组件:通过构造函数定义需要接收的参数(推荐用 final 保证不可变);
  • 父组件:创建子组件时,通过构造函数传递数据
import 'package:flutter/material.dart';

// 子组件(接收父组件传递的值)
class ChildWidget extends StatelessWidget {
  // 1. 定义接收的参数(final + 构造函数必填)
  final String title;
  final int count;
  final Color bgColor;

  // 2. 构造函数(推荐用 required 标记必填参数)
  const ChildWidget({
    super.key,
    required this.title,
    required this.count,
    this.bgColor = Colors.blue, // 可选参数,设置默认值
  });

  
  Widget build(BuildContext context) {
    return Container(
      color: bgColor,
      padding: const EdgeInsets.all(16),
      child: Column(
        children: [
          Text("父组件传递的标题:$title"),
          Text("父组件传递的数字:$count"),
        ],
      ),
    );
  }
}

// 父组件(传递值给子组件)
class ParentWidget extends StatelessWidget {
  const ParentWidget({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("父传子示例")),
      body: Center(
        // 3. 创建子组件时传递参数
        child: ChildWidget(
          title: "我是父组件给的标题",
          count: 99,
          bgColor: Colors.lightBlue, // 覆盖默认值
        ),
      ),
    );
  }
}

子组件调用父组件(传值 / 调方法)

子组件不能直接访问父组件的属性 / 方法,核心实现方式是父组件将函数(回调)传递给子组件,子组件调用该函数(本质是 “子触发父的逻辑”)。

import 'package:flutter/material.dart';

// 子组件(调用父组件的回调函数传值)
class ChildWidget extends StatelessWidget {
  // 1. 接收父组件传递的回调函数
  final Function(String) onValueChanged;
  final Function() onButtonClick;

  const ChildWidget({
    super.key,
    required this.onValueChanged,
    required this.onButtonClick,
  });

  
  Widget build(BuildContext context) {
    return Column(
      children: [
        // 点击按钮:调用父组件的回调,传递子组件的数值
        ElevatedButton(
          onPressed: () {
            // 2. 子组件主动调用父组件的函数,传递数据
            onValueChanged("我是子组件传递给父的值");
          },
          child: const Text("子组件传值给父"),
        ),
        ElevatedButton(
          onPressed: () {
            // 3. 子组件调用父组件的无参方法
            onButtonClick();
          },
          child: const Text("子组件调用父组件方法"),
        ),
      ],
    );
  }
}

// 父组件(定义回调函数,接收子组件的值/响应调用)
class ParentWidget extends StatefulWidget {
  const ParentWidget({super.key});

  
  State<ParentWidget> createState() => _ParentWidgetState();
}

class _ParentWidgetState extends State<ParentWidget> {
  String _childData = "暂无数据";

  // 4. 父组件定义回调函数(处理子组件传递的值)
  void _handleChildValue(String value) {
    setState(() {
      _childData = value; // 更新父组件的状态
    });
    print("父组件收到子组件的值:$value");
  }

  // 5. 父组件定义被调用的方法
  void _parentMethod() {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text("父组件的方法被子组件调用了!")),
    );
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("子调用父示例")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text("子组件传递的值:$_childData"),
            const SizedBox(height: 20),
            // 6. 将父组件的函数传递给子组件
            ChildWidget(
              onValueChanged: _handleChildValue,
              onButtonClick: _parentMethod,
            ),
          ],
        ),
      ),
    );
  }
}

子组件是 StatefulWidget,父组件调用子组件方法

如果需要父组件主动调用子组件的方法(比如子组件有一个 “重置” 方法,父组件按钮触发),需要用 GlobalKey 或 Callback 实现,这里讲最常用的 GlobalKey 方式:

import 'package:flutter/material.dart';

// 子组件(提供可被父组件调用的方法)
class ChildWidget extends StatefulWidget {
  // 1. 定义 GlobalKey,关联子组件的 State
  static final GlobalKey<_ChildWidgetState> childKey = GlobalKey<_ChildWidgetState>();

  const ChildWidget({super.key = childKey}); // 绑定Key

  
  State<ChildWidget> createState() => _ChildWidgetState();
}

class _ChildWidgetState extends State<ChildWidget> {
  int _childCount = 0;

  // 2. 子组件的公开方法(供父组件调用)
  void resetCount() {
    setState(() {
      _childCount = 0;
    });
    print("子组件的count被父组件重置了");
  }

  // 子组件的自增方法
  void incrementCount() {
    setState(() {
      _childCount++;
    });
  }

  
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text("子组件的count:$_childCount"),
        ElevatedButton(
          onPressed: incrementCount,
          child: const Text("子组件自增"),
        ),
      ],
    );
  }
}

// 父组件(调用子组件的方法)
class ParentWidget extends StatelessWidget {
  const ParentWidget({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("父调用子示例")),
      body: Center(
        child: ColumnChildWidget
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const ChildWidget(), // 3. 创建子组件(已绑定Key)
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                // 4. 父组件通过 GlobalKey 调用子组件的方法
                ChildWidget.childKey.currentState?.resetCount();
              },
              child: const Text("父组件调用子组件的重置方法"),
            ),
          ],
        ),
      ),
    );
  }
}

void main() => runApp(const MaterialApp(home: ParentWidget()));

通过回调主动监听(有状态子组件) 子组件监听父组件值更新

import 'package:flutter/material.dart';

// 子组件:有状态,主动监听父组件参数变化
class ChildWidget extends StatefulWidget {
  final int parentCount;

  const ChildWidget({
    super.key,
    required this.parentCount,
  });

  
  State<ChildWidget> createState() => _ChildWidgetState();
}

class _ChildWidgetState extends State<ChildWidget> {
  int _localCount = 0; // 子组件本地状态

  // 核心生命周期:当父组件传递的参数变化时触发
  
  void didUpdateWidget(covariant ChildWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    // 对比新旧参数,确认值真的变化了(避免无意义的逻辑执行)
    if (widget.parentCount != oldWidget.parentCount) {
      print("子组件监听到父组件count变化:${oldWidget.parentCount}${widget.parentCount}");
      
      // 执行额外逻辑:比如更新本地状态、发起请求、播放动画等
      setState(() {
        _localCount = widget.parentCount * 2; // 子组件根据父值更新本地数据
      });
      
      // 其他逻辑:比如弹提示、调用方法等
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text("父组件count更新为:${widget.parentCount}")),
      );
    }
  }

  
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(16),
      color: Colors.lightGreen,
      child: Column(
        children: [
          Text("父组件count:${widget.parentCount}"),
          Text("子组件本地计算值:$_localCount"),
        ],
      ),
    );
  }
}

// 父组件:和基础示例一致,维护动态count
class ParentWidget extends StatefulWidget {
  const ParentWidget({super.key});

  
  State<ParentWidget> createState() => _ParentWidgetState();
}

class _ParentWidgetState extends State<ParentWidget> {
  int _count = 0;

  void _incrementCount() {
    setState(() {
      _count++;
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("主动监听父组件值更新")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ChildWidget(parentCount: _count),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: _incrementCount,
              child: const Text("增加父组件count"),
            ),
          ],
        ),
      ),
    );
  }
}

void main() => runApp(const MaterialApp(home: ParentWidget()));

核心逻辑

  • didUpdateWidget 是 StatefulWidget 的生命周期方法,仅在父组件传递的参数变化时触发;
  • 通过对比 oldWidget(旧参数)和 widget(新参数),可以精准判断哪些值发生了变化;
  • 在方法内可以执行任意自定义逻辑(更新本地状态、弹提示、调用方法等),实现 “主动监听”。

注意事项

  • 子调用父的核心逻辑:父组件传递 “函数” 给子组件,子组件执行该函数(可传参),本质是 “回调”,而非子组件直接访问父组件;
  • GlobalKey 注意点:
    • 仅用于父调用子的场景,不要滥用(可能影响性能);
    • currentState 可能为 null,需加 ? 空安全判断;
  • 状态管理:如果组件层级较深(超过父子),不建议用回调 / GlobalKey,推荐用 Provider/GetX/Riverpod 等状态管理库;
  • 不可变原则:父传子的参数推荐用 final,如果需要修改,通过回调通知父组件更新状态,再重新传值给子组件(单向数据流)。
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐