【问题标题】:How to interactif with a child Stateful Widget from a parent Stateless Widget?如何与来自父无状态小部件的子有状态小部件进行交互?
【发布时间】:2022-11-18 09:12:40
【问题描述】:

语境 :

假设我有一个自定义的 DisplayElapsedTime 小部件,它是 Stateful 并拥有一个 Text 小部件。对于 Timer,每隔 1 秒,文本值就会更新为 Stopwatch 给出的当前 elapsed 时间。

现在,假设我有一个页面是 Stateless 并且有一个 DisplayElapsedTime 小部件。

我想做什么:

  1. 单击我页面中的“开始”按钮,我想启动DisplayElapsedTime(这意味着启动StopwatchTimer)。

  2. 在我的页面上,我还想“随时”访问Stopwatchelapsed 时间值。

    为什么我很难过:

    到目前为止(参见:I use Stateless Widget alongside BLoC almost everytime. Am I wrong?),我几乎总是使用Stateless Widget 和模式 BLoC,而从未使用过Stateful。目前,拥有非常长和复杂的小部件,我开始感觉到不使用两个世界中更好的一个的“限制”。但是我不太完全理解小部件之间应该如何交互。

    我真的无法在任何地方找到我的问题的解决方案(或者我真的不擅长搜索)。但是,当然,我不可能是第一个想要从 Stateless 小部件“控制” Stateful 小部件的人,对吧?

    非常感谢您的帮助。

【问题讨论】:

    标签: flutter timer stopwatch statefulwidget statelesswidget


    【解决方案1】:

    如果我正确理解你的问题,让我尝试使用有史以来最熟悉的应用程序开始解释这个问题。

    此 sn-p 包含一个 StatefulWidget,它使用其 setState 方法控制其重建能力_incrementCounter.因此,每当StatefulWidget打电话给方法在 - 的里面StatefulWidget.

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: const MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({super.key, required this.title});
      final String title;
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      int _counter = 0;
    
      void _incrementCounter() {
        setState(() {
          _counter++;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                const Text(
                  'You have pushed the button this many times:',
                ),
                Text(
                  '$_counter',
                  style: Theme.of(context).textTheme.headlineMedium,
                ),
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: _incrementCounter,
            tooltip: 'Increment',
            child: const Icon(Icons.add),
          ), // This trailing comma makes auto-formatting nicer for build methods.
        );
      }
    }
    

    一个StatefulWidget可以完全重建自己。要让另一个小部件重建父小部件,您需要拥有该小部件的设置状态功能。这可以使用回调函数.一个回调函数由父部件制作并传递给子部件。所以,在下面的例子中,我做了一个StatelessWidget按钮,我想控制它的父窗口小部件。所以,我把它传递给回调函数;请注意,我给出:

    ExampleStlessWidget(counter: _counter, fx: _incrementCounter),
    

    并不是:

    ExampleStlessWidget(counter: _counter, fx: _incrementCounter()),
    

    通过_incrementCounter()括号在传递时调用它,而_incrementCounter允许它在小部件树的下游被调用。

    使用回调函数在子部件中通过调用它(注意括号)。

    onPressed: () {
                    fx();
                  },
    

    这是新代码

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: const MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({super.key, required this.title});
      final String title;
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      int _counter = 0;
    
      void _incrementCounter() {
        setState(() {
          _counter++;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: ExampleStlessWidget(counter: _counter, fx: _incrementCounter),
          floatingActionButton: FloatingActionButton(
            onPressed: _incrementCounter,
            tooltip: 'Increment',
            child: const Icon(Icons.add),
          ), // This trailing comma makes auto-formatting nicer for build methods.
        );
      }
    }
    
    class ExampleStlessWidget extends StatelessWidget {
      const ExampleStlessWidget({
        super.key,
        required int counter,
        required this.fx,
      }) : _counter = counter;
    
      final int _counter;
      final Function fx;
    
      @override
      Widget build(BuildContext context) {
        return Column(
          children: [
            Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  const Text(
                    'You have pushed the button this many times:',
                  ),
                  Text(
                    '$_counter',
                    style: Theme.of(context).textTheme.headlineMedium,
                  ),
                ],
              ),
            ),
            ElevatedButton(
              onPressed: () {
                fx();
              },
              child: const Text('Click me'),
            ),
          ],
        );
      }
    }
    

    一个集团涉及一个继承的小部件,它允许监视整个小部件树的状态并根据该状态重建特定的小部件。如果您不看一个工具重建小部件的能力是好是坏,那将会有所帮助。最好看看 StatefulWidgets 和集团作为不同工作的不同工具。

    我希望这有帮助。快乐的编码。

    【讨论】:

      猜你喜欢
      • 2021-02-16
      • 2021-12-15
      • 2020-01-05
      • 2021-07-25
      • 2021-09-21
      • 2021-06-11
      • 2019-10-06
      • 1970-01-01
      • 2018-09-01
      相关资源
      最近更新 更多