flutter-InheritedWidget

58 阅读3分钟

flutter 中我们可能会存在这样一个需求,我有一个公共信息需要保存,同时应用到整个项目或者是一个页面,flutter 就提供了这个一个组件 InheritedWidget,同时其也是 provider 框架的基础,下面就简单介绍一下

provider地址:这里不介绍,下篇文章介绍

demo地址(inherited文件夹):里面也有 provider 的案例

InheritedWidget

InheritedWidget在我们身边非常常见,例如: pull_to_refreshprovider等,可以在我们的 MaterialApp外侧包裹一个组件,里面就用到了InheritedWidget,这个就是全局共享信息用的,且共享信息更新的话,使用了公共信息的组件也会自动更新内容

话不多说了,先创建一个 InheritedWidget 子类

image.png

创建完成之后我们完善一下,默认构造方法ofupdateShouldNotify方法

of 方法就和 Navigator.of 一样,可以用来通过类名 + of 获取实例

updateShouldNotify 用于根据内部属性判断是否需要通知外部更新,触发更新时会响应外部组件的 didChangeDependencies方法,可以用来做一些事请

//继承自 ProxyWidget、Widget 无状态,如果有状态外面套一个 StatefulWidget就可以动态动态修改内容了😂
//假设我们仅仅用于个人页面
class MyInheritedWidget extends InheritedWidget {
  //用来保存我们的对象,要标记为 final,里面不能直接修改,可以通过修改外面传递的值来修改该内容触发更新
  final String username;

   const MyInheritedWidget({
    Key? key,
    required this.username,
    required Widget child,
  }) : super(key: key, child: child);

  //就像 Navigator.of(context)一样获取,用于调用内部参数
   static MyInheritedWidget of(BuildContext context) {
    final MyInheritedWidget? result = context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
    assert(result != null, 'No MyInherited found in context');
    return result!;
  }

  //更新时用于判断、过滤是否通知外部更新
  //如果外部使用的是 StatefulWidget,变更时会调用didChangeDependencies,以此来通知对应页面进行其他调整
  @override
  bool updateShouldNotify(MyInheritedWidget oldWidget) {
    //返回为true就是通知更新,否则不更新
    //这里我们过滤一下,如果值没发生改变,我们就不通知外面即可
    return username != oldWidget.username;
  }
}

下面我们试用一下自己封装的,同时应用到一个 StatefulWidgetStatelessWidget,都完全ok,里面也都能够接收到内容的变更

同时通过案例也可以看到,使用局限性也挺大的,需要通过更新外部传入值,从而更新其他所有页面内容,当跨页面太多时,就不好用了,因此比较适用于静态数据

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  //作为传入 InheritedWidget 的参数,更改其来通知其他页面更新
  String userName = '默认userName';

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print("didChangeDependencies");
  }

  @override
  Widget build(BuildContext context) {
    //就像这样一样,外面嵌套一个 StatefulWidget 就可以随便修改 InheritedWidget 属性,从而触发属性更新,再应用到指定地方
    return MyInheritedWidget(
      username: userName, //通过外面修改该参数,间接修改里面内容
      child: Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: SafeArea(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              const TestWidget(),
              const TestFullWidget(),
              IconButton(
                onPressed: () {
                  setState(() {
                    userName = '分享了';
                  });
                },
                icon: const Icon(
                  Icons.share,
                  color: Colors.green,
                ),
              ),
              IconButton(
                onPressed: () {
                  setState(() {
                    userName = '邮件了';
                  });
                },
                icon: const Icon(
                  Icons.mail,
                  color: Colors.green,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Text(MyInheritedWidget.of(context).username, textAlign: TextAlign.center,);
  }
}

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

  @override
  State<TestFullWidget> createState() => _TestFullWidgetState();
}

class _TestFullWidgetState extends State<TestFullWidget> {

  @override
  void initState() {
    super.initState();
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {
    return Text(MyInheritedWidget.of(context).username, textAlign: TextAlign.center);
  }
}

最后

通过上面使用和案例,可以看出来,若其只用静态数据展示,还是非常优秀的,例如:一些全局数据等,一些三方的全局信息(一些三方自己也这么用)

如果需要多个页面有联动更新,那么这个就不是那么好使用了,还需要改进才行,下一章的 provider 将会完美解决这个问题