美文网首页
Flutter 之 数据传递

Flutter 之 数据传递

作者: Cat_uncle | 来源:发表于2022-03-09 21:46 被阅读0次

    InheritedWidget 是 Flutter 中的一个功能型 Widget,适用于在 Widget 树中共享数据的场景。

    class CounterPage extends StatefulWidget {

    CounterPage({Key ? key}) :super(key: key);

    @override

      _CounterPageState createState() =>_CounterPageState();

    }

    //

    class _CounterPageState extends State {

    int count =0;

    //3我们通过 InheritedCountContainer.of 方法找到它,获取计数状态 count 并展示:

      void _incrementCounter() => setState(() {count++;});// 修改计数器

      @override

      Widget build(BuildContext context) {

    //2我们使用 CountContainer 作为根节点,并用 0 初始化 count。

        return CountContainer(

    model:this,

    increment: _incrementCounter,// 提供修改数据的方法

            child:Counter()

    );

    }

    }

    /*1

    * 首先,为了使用 InheritedWidget,我们定义了一个继承自它的新类 CountContainer。

    * 然后,我们将计数器状态 count 属性放到 CountContainer 中,

    * 并提供了一个 of 方法方便其子 Widget 在 Widget 树中找到它。

    * 最后,我们重写了 updateShouldNotify 方法,这个方法会在 Flutter

    *  判断 InheritedWidget 是否需要重建,从而通知下层观察者组件更新数据时被调用到。

    * 在这里,我们直接判断 count 是否相等即可。

    * */

    class CountContainer extends InheritedWidget {

    static CountContainer?of(BuildContext context) {

    return context.dependOnInheritedWidgetOfExactType();

    }

    final _CounterPageState model;// 直接使用 MyHomePage 中的 State 获取数据

      final Function()increment;

    CountContainer({

    Key ?key,

    required this.model,

    required this.increment,

    required Widget child,

    }):super(key: key, child: child);

    @override

      bool updateShouldNotify(CountContainer oldWidget) =>model != oldWidget.model;

    }

    class Counter extends StatelessWidget {

    @override

      Widget build(BuildContext context) {

    // 获取 InheritedWidget 节点

        CountContainer?state =CountContainer.of(context);

    return Scaffold(

    appBar:AppBar(

    title:Text("InheritedWidget demo"),

    ),

    body:Text(

    'You have pushed the button this many times: ${state?.model.count}',// 关联数据读方法

          ),

    floatingActionButton:FloatingActionButton(onPressed:state?.increment),// 关联数据修改方法

        );

    }

    }

    Notification 是 Flutter 中进行跨层数据共享的另一个重要的机制。如果说 InheritedWidget 的数据流动方式是从父 Widget 到子 Widget 逐层传递,那 Notificaiton 则恰恰相反,数据流动方式是从子 Widget 向上传递至父 Widget。这样的数据传递机制适用于子 Widget 状态变更,发送通知上报的场景。

    class CustomNotification extends Notification {

    CustomNotification(this.msg);

    final String msg;

    }

    class CustomChild extends StatelessWidget {

    @override

      Widget build(BuildContext context) {

    return RaisedButton(

    //按钮点击时分发通知

          onPressed: () =>CustomNotification("Hi").dispatch(context),

    child:Text("Fire Notification"),

    );

    }

    }

    class NotificationWidget extends StatefulWidget {

    @override

      StatecreateState()=>_NotificationState();

    }

    class _NotificationState extends State {

    String _msg ="通知:";

    @override

      Widget build(BuildContext context) {

    //监听通知

        return NotificationListener(

    onNotification: ( notification) {

    setState(() {_msg += notification.msg+"  ";});

    return true;

    },

    child:Column(

    mainAxisAlignment:MainAxisAlignment.center,

    children: [Text(_msg),CustomChild()],

    )

    );

    }

    }

    无论是 InheritedWidget 还是 Notificaiton,它们的使用场景都需要依靠 Widget 树,也就意味着只能在有父子关系的 Widget 之间进行数据共享。但是,组件间数据传递还有一种常见场景:这些组件间不存在父子关系。这时,事件总线 EventBus 就登场了。

    事件总线是在 Flutter 中实现跨组件通信的机制。它遵循发布 / 订阅模式,允许订阅者订阅事件,当发布者触发事件时,订阅者和发布者之间可以通过事件进行交互。发布者和订阅者之间无需有父子关系,甚至非 Widget 对象也可以发布 / 订阅。

    // 所以在这里,我们传输数据的载体就选择了一个有字符串属性的自定义事件类 CustomEvent:

    class CustomEvent {

    String msg;

    CustomEvent(this.msg);

    }

    // 建立公共的 event bus

    EventBus eventBus =new EventBus();

    /*

    * 我们定义了一个全局的 eventBus 对象,并在第一个页面监听了 CustomEvent 事件,

    * 一旦收到事件,就会刷新 UI。

    * 需要注意的是,千万别忘了在 State 被销毁时清理掉事件注册,

    * 否则你会发现 State 永远被 EventBus 持有着,无法释放,从而造成内存泄漏:

    *

    *  */

    class FirstPage extends StatefulWidget {

    @override

      StatecreateState()=>_FirstPageState();

    }

    class _FirstPageState extends State {

    String msg ="通知:";

    late StreamSubscription subscription;

    @override

      void initState() {

    //监听CustomEvent事件,刷新UI

        subscription =eventBus.on().listen((event) {

    print(event.msg);

    setState(() {

    msg += event.msg;

    });

    });

    super.initState();

    }

    dispose() {

    subscription.cancel();//State销毁时,清理注册

        super.dispose();

    }

    @override

      Widget build(BuildContext context) {

    return Scaffold(

    appBar:AppBar(title:Text("First Page"),),

    body:Text(msg),

    floatingActionButton:FloatingActionButton(onPressed: ()=>Navigator.push(context,MaterialPageRoute(builder: (context) =>SecondPage()))),

    );

    }

    }

    //我们在第二个页面以按钮点击回调的方式,触发了 CustomEvent 事件:

    class SecondPage extends StatelessWidget {

    Widget build(BuildContext context) {

    return Scaffold(

    appBar:AppBar(title:Text("Second Page"),),

    body:RaisedButton(

    child:Text('Fire Event'),

    // 触发CustomEvent事件

              onPressed: ()=>eventBus.fire(CustomEvent("hello"))

    ),

    );

    }

    }

    相关文章

      网友评论

          本文标题:Flutter 之 数据传递

          本文链接:https://www.haomeiwen.com/subject/vhqxdrtx.html