如何在 StatelessWidget 中更改 StatefulWidget 的状态?

Posted

技术标签:

【中文标题】如何在 StatelessWidget 中更改 StatefulWidget 的状态?【英文标题】:How to change a State of a StatefulWidget inside a StatelessWidget? 【发布时间】:2019-03-26 14:21:46 【问题描述】:

只是测试颤振。下面的代码示例是一个非常简单的颤振应用程序。问题是我不知道如何调用 TestTextState 类中的 setState() 函数,以便在每次按下更改按钮时更改文本。

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget 
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) 
    return new MaterialApp(
      title: 'Test app',
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text("Test"),
        ),
        body: new Test(),
      ),
    );
  


class Test extends StatelessWidget 

  final TestText testText = new TestText();

  void change() 
    testText.text == "original" ? testText.set("changed") : testText.set("original");
  

  @override
  Widget build(BuildContext context) 
    return new Column(
      children: [
        testText,
        new RaisedButton(
            child: new Text("change"),
            onPressed: () => change(),
        ),
      ]
    );
  


class TestText extends StatefulWidget 

  String text = "original";

  void set(String str) 
    this.text = str;
  

  @override
  TestTextState createState() => new TestTextState();


class TestTextState extends State<TestText> 

  @override
  Widget build(BuildContext context) 
    return new Text(this.widget.text);
  

【问题讨论】:

【参考方案1】:

我通过将 _TestTextState 初始化为 TestText 小部件的最终属性来解决这个问题,它允许在按下更改按钮时简单地更新状态。这似乎是一个简单的解决方案,但我不确定这是否是一个好习惯。

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget 
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) 
    return new MaterialApp(
      title: 'Test app',
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text("Test"),
        ),
        body: new Test(),
      ),
    );
  


class Test extends StatelessWidget 

  final _TestText text = new _TestText();

  @override
  Widget build(BuildContext context) 
    return new Column(
        children: [
          text,
          new RaisedButton(
            child: new Text("change"),
            onPressed: () => text.update(),
          ),
        ]
    );
  


class TestText extends StatefulWidget 

  final _TestTextState state = new _TestTextState();

  void update() 
    state.change();
  

  @override
  _TestTextState createState() => state;


class _TestTextState extends State<TestText> 

  String text = "original";

  void change() 
    setState(() 
      this.text = this.text == "original" ? "changed" : "original";
    );
  

  @override
  Widget build(BuildContext context) 
    return new Text(this.text);
  

【讨论】:

【参考方案2】:

基于您现有代码的解决方案

class Test extends StatelessWidget 
  final StreamController<String> streamController = StreamController<String>.broadcast();

  @override
  Widget build(BuildContext context) 
    final TestText testText = TestText(streamController.stream);
    return new Column(children: [
      testText,
      new RaisedButton(
        child: Text("change"),
        onPressed: () 
          String text = testText.text == "original" ? "changed" : "original";
          streamController.add(text);
        ,
      ),
    ]);
  


class TestText extends StatefulWidget 
  TestText(this.stream);
  final Stream<String> stream;
  String text = "original";

  @override
  TestTextState createState() => new TestTextState();


class TestTextState extends State<TestText> 
  @override
  void initState() 
    widget.stream.listen((str) 
      setState(() 
        widget.text = str;
      );
    );
    super.initState();
  
  @override
  Widget build(BuildContext context) 
    return Text(widget.text);
  

但这不是最好的主意 - 在 Stateful Widget 中使用 non-final 字段

附: 你也可以使用这个——scoped_model

【讨论】:

感谢您的超快速响应。添加 StreamController 似乎是个好主意。没有非最终字段的解决方案会是什么样子?这甚至可能吗? 将此字段存储在TestTextState 中,并在listen 中检查text 的当前值- 例如。在这种情况下,您可以将任何数据发送到流 - 类型无关紧要【参考方案3】:

他们是没有办法这样做的。您必须如何将 StatelessWidget 转换为 StatefulWidget

【讨论】:

感谢您的重播。因此,如果我的应用程序中有多个不同的页面并且所有页面都共享一个动态文本小部件,这是否意味着我必须将所有屏幕转换为 StatefulWidgets?它将如何反映性能?

以上是关于如何在 StatelessWidget 中更改 StatefulWidget 的状态?的主要内容,如果未能解决你的问题,请参考以下文章

Flutter:如何将变量从 StatelessWidget 传递到 StatefulWidget

如何将数据从 StatelessWidget 传递到 StatefulWidget?

Flutter中StatelessWidget调用StatefulWidget的函数

如何从 StatelessWidget 中的 StatefulWidget 访问变量?

调度第一个 bloc 事件或 cubit 方法,在 StatelessWidget 内的页面开始

当状态随 Provider 发生变化时,使用 StatelessWidget 是不是安全?