flutter3.0学习笔记

InheritedWidget

Preview

在Flutter中如何在不同的Widget传递数据?如果只是简单的上下级关系,我们可以把数据添加到下级的Widget的函数中。但是如果传递数据的Widget层级相隔太远,那么不可能一层一层传递。Flutter提供了一种在Widget树中自上而下传递数据的方法InheritedWidget

  • 使用InheritedWidget

因为InheritedWidget是一个抽象类,所以需要创建一个扩展它的类。

扩展InheritedWidget需要覆盖updateShouldNotify方法。那么什么是updateShouldNotify方法: updateShouldNotify用于控制依赖于该InheritedWidget的组件是否需要重建。如果updateShouldNotify的值是true,则当InheritedWidget发生变化时,依赖于该InheritedWidgetWidget会被重建,其元素的didChangeDependencies函数会被调用,从而更新子Widget中的显示。反之,则不会重建依赖于该InheritedWidgetWidget

bool updateShouldNotify(covariant InheritedWidget oldWidget);
  • 实现of方法

of约定是在InheritedWidget上提供一个静态方法,该方法 调用BuildContext.dependOnInheritedWidgetOfExactType

下面是一个名为Info的类,继承InheritedWidget。它覆盖updateShouldNotify并有一个静态方法of

class Info extends InheritedWidget {
  final int score;//需要在子树中共享的数据
  const Info({
    Key? key,
    required this.score,
    required Widget child,
  }) : super(key: key,child: child);

  //创建Info方法从子树中的widget获取共享数据
  static Info? of(BuildContext context){
    return context.dependOnInheritedWidgetOfExactType<Info>();
  }
  //该回调决定当data发生变化时,是否通知子树中依赖data的Widget重新build
  @override
  bool updateShouldNotify(covariant Info oldWidget){
    return score != oldWidget.score;
  }
}
  • 调用of方法

使用该of方法时,context必须是 InheritedWidget的后代,这意味着它必须在树中的InheritedWidget “下方”。

下面创建名为CurrentScore的组件,他是Info的子组件,用来显示分数score文本,

class CurrentScore extends StatelessWidget{
  const CurrentScore({super.key});
  @override
  Widget build(BuildContext context){
    //调用Info中的共享数据
    final Info? info = Info.of(context);
    return Container(
      child: Text('$info?.score'),
    );
  }
}
  • 完整代码
import 'dart:math';

import 'package:flutter/material.dart';

class InheritedWidgetPage extends StatefulWidget {
  const InheritedWidgetPage({Key? key}) : super(key: key);

  @override
  State<InheritedWidgetPage> createState() => _InheritedWidgetPageState();
}

class _InheritedWidgetPageState extends State<InheritedWidgetPage> {
  late  int _score = 50;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('InheritedWidget'),),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Info(
              score: _score,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: const [
                  Icon(Icons.score),
                  CurrentScore(),
                ],
              )
            ),
            OutlinedButton(
              onPressed: (){
                //点击改变分数
                setState(() {
                  _score = Random().nextInt(100);
                });
              },
              child: const Text('点击改变分数'),
            )
          ],
        ),
      ),
    );
  }
}


class Info extends InheritedWidget {
  final int score;//需要在子树中共享的数据
  const Info({
    Key? key,
    required this.score,
    required Widget child,
  }) : super(key: key,child: child);
  //创建Info方法从子树中的widget获取共享数据
  static Info? of(BuildContext context){
    return context.dependOnInheritedWidgetOfExactType<Info>();
  }
  //该回调决定当data发生变化时,是否通知子树中依赖data的Widget重新build
  @override
  bool updateShouldNotify(covariant Info oldWidget){
    return score != oldWidget.score;
  }
}

class CurrentScore extends StatelessWidget{
  const CurrentScore({super.key});
  @override
  Widget build(BuildContext context){
    //调用Info中的共享数据
    final Info? info = Info.of(context);
    return Container(
      child: Text('${info?.score}'),
    );
  }
}

相当父组件传值给子组件,子组件接受并且显示。 inh.gif