Dart 将函数从窗口小部件触发到状态对象

Dart 将函数从窗口小部件触发到状态对象,dart,flutter,Dart,Flutter,这是该场景的简化版本: class ParentWdiegt extends StatelessWidget{ // // floatinActionButton: FloatingActionButtonWidget(onPressed:()=>CustomWidgetState.someMethod(someValue)) // //somewhere in the ParentWidget tree child: CustomWidget() //is stateful } 自定义

这是该场景的简化版本:

class ParentWdiegt extends StatelessWidget{
//
//
floatinActionButton: FloatingActionButtonWidget(onPressed:()=>CustomWidgetState.someMethod(someValue))
//
//somewhere in the ParentWidget tree
child: CustomWidget() //is stateful
}
自定义WidgetState

class CustomWidgetState extends State<CustomWidget>{
//trigger this function when FAB is pressed in parent widget
someMethod(SomeValue) {//}
}
类CustomWidgetState扩展状态{
//在父窗口小部件中按下FAB时触发此功能
someMethod(SomeValue){/}
}

是否有任何方法可以在按下FAB时在要触发的状态对象中公开
someMethod
,而不使用
InheritedWidget

您可以使用
GlobalKey

// some global place
final customWidgetKey = new GlobalKey<CustomWidgetState>();


GlobalKey
允许轻松访问任何小部件的状态;避免它。 小部件不应与其他小部件直接交互。这是颤振的核心原理之一

颤振使用反应式编程代替。小部件通过提交事件相互通信。而不是直接编辑所需的小部件

明显的好处是小部件保持独立。可能有几十个小部件可以使用相同的原理相互通信

我已经举了一个例子,说明如何使两个不同的小部件共享一个公共的可编辑值

如果您想调用方法,则使用相同的原则:在小部件之间共享
Listenable
Stream
。但不使用
AnimatedWidget
StreamBuilder
进行监听。 相反,我们将手动执行侦听(这需要更多的样板文件)来触发自定义函数

下面是一个使用
Stream
的示例

import 'dart:async';
import 'package:flutter/material.dart';

class ParentWidget extends StatefulWidget {
  @override
  _ParentWidgetState createState() => _ParentWidgetState();
}

class _ParentWidgetState extends State<ParentWidget> {
  final changeNotifier = new StreamController.broadcast();

  @override
  void dispose() {
    changeNotifier.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return new Column(
      children: <Widget>[
        new AnotherWidget(
          shouldTriggerChange: changeNotifier.stream,
        ),
        new RaisedButton(
          child: new Text("data"),
          onPressed: () => changeNotifier.sink.add(null),
        )
      ],
    );
  }
}

class AnotherWidget extends StatefulWidget {
  final Stream shouldTriggerChange;

  AnotherWidget({@required this.shouldTriggerChange});

  @override
  _AnotherWidgetState createState() => _AnotherWidgetState();
}

class _AnotherWidgetState extends State<AnotherWidget> {
  StreamSubscription streamSubscription;

  @override
  initState() {
    super.initState();
    streamSubscription = widget.shouldTriggerChange.listen((_) => someMethod());
  }

  @override
  didUpdateWidget(AnotherWidget old) {
    super.didUpdateWidget(old);
    // in case the stream instance changed, subscribe to the new one
    if (widget.shouldTriggerChange != old.shouldTriggerChange) {
      streamSubscription.cancel();
      streamSubscription = widget.shouldTriggerChange.listen((_) => someMethod());
    }
  }

  @override
  dispose() {
    super.dispose();
    streamSubscription.cancel();
  }

  void someMethod() {
    print('Hello World');
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}
导入'dart:async';
进口“包装:颤振/材料.省道”;
类ParentWidget扩展了StatefulWidget{
@凌驾
_ParentWidgetState createState()=>\u ParentWidgetState();
}
类_ParentWidgetState扩展状态{
final changeNotifier=new StreamController.broadcast();
@凌驾
无效处置(){
changeNotifier.close();
super.dispose();
}
@凌驾
小部件构建(构建上下文){
返回新列(
儿童:[
新的另一个小部件(
shouldTriggerChange:changeNotifier.stream,
),
新升起的按钮(
子项:新文本(“数据”),
onPressed:()=>changeNotifier.sink.add(null),
)
],
);
}
}
类AnotherWidget扩展StatefulWidget{
最终流应触发更改;
另一个小部件({@required this.shouldTriggerChange});
@凌驾
_另一个WidgetState createState()=>另一个WidgetState();
}
类\u另一个WidgetState扩展状态{
流订阅流订阅;
@凌驾
initState(){
super.initState();
streamSubscription=widget.shouldTriggerChange.listen((\u)=>someMethod());
}
@凌驾
didUpdateWidget(另一个旧小部件){
super.diupdatewidget(旧);
//如果流实例已更改,请订阅新实例
if(widget.shouldTriggerChange!=old.shouldTriggerChange){
streamSubscription.cancel();
streamSubscription=widget.shouldTriggerChange.listen((\u)=>someMethod());
}
}
@凌驾
处置{
super.dispose();
streamSubscription.cancel();
}
void方法(){
打印(“Hello World”);
}
@凌驾
小部件构建(构建上下文){
返回容器();
}
}

在本例中,只要单击由
\u ParentWidgetState
实例化的
raised按钮,就会调用另一个小部件的
someMethod

尝试存储小部件的状态,然后访问

class MySFWidget extends StatefulWidget {
  SFWidgetState currState;

  @override
  SFWidgetState createState(){
    currState = new SFWidgetState();
    return currState;
  };

}

class SFWidgetState extends State<MySFWidget> {

  int prop;

  void SomeMethod(){
    // DO Something
  }

  @override
  Widget build(BuildContext context) {
    return null;
  }

}
类MySFWidget扩展StatefulWidget{
SFWidgetState当前状态;
@凌驾
SFWidgetState createState(){
currState=新的SFWidgetState();
返回状态;
};
}
类SFWidgetState扩展了状态{
int prop;
void方法(){
//做点什么
}
@凌驾
小部件构建(构建上下文){
返回null;
}
}
然后,通过以下方式访问其属性或调用方法:

myWidgetInstance.currState.prop


myWidgetInstance.currState.SomeMethod()

试试看,在状态上调用某个东西真的有意义吗?@RémiRousselet我有一个
CustomWidget
有状态的
CustomWidgetState
我想把所有状态操作逻辑都保存在
CustomWidgetState
中。因此,调用
CustomWidgetState
中的状态操作逻辑的一种情况是,在我的问题中,通过按下其他小部件(如
ParentWidget
)中的一些按钮来完成的。我这样做的原因是我不想在
state
对象之外构建任何状态操作逻辑。如果你有更好的方法来实现这一点,我将非常感谢你的帮助。有意义吗?valueListener可以是clickevent。而且
CustomWidgetState
订阅clickEvent to do Stuff看起来很有趣,但据我所知,这只适用于字段,不能触发方法,对吗?通常是个坏主意。首选
上下文。对我来说,ancestorStateOfType
ancestorStateOfType
似乎很脆弱,但感谢您指出,我不知道这种方法。这就是我们如何使用
导航器获得
NatigatorState
。无论如何
GlobalKey
在视图中必须是唯一的;这很不方便。特别是在这种情况下,
Navigator
是一种更为具体的用例,在这种情况下,可以假定一些层次结构。我没有看到关于特定用例的提示。不确定“特别是在那种情况下”是什么意思-你是指你的
Navigator
示例,还是你从我可能遗漏的问题中得出了什么?我的意思是,可能不止一个小部件想要对按钮点击做出反应。但是使用
GlobalKey
您需要提前知道整个小部件树是如何工作的。我认为我添加的答案很好地解释了我在这个主题上的思路。这对我不起作用,真的不知道,我基本上是复制和粘贴的。如果一个有状态的小部件初始化
import 'dart:async';
import 'package:flutter/material.dart';

class ParentWidget extends StatefulWidget {
  @override
  _ParentWidgetState createState() => _ParentWidgetState();
}

class _ParentWidgetState extends State<ParentWidget> {
  final changeNotifier = new StreamController.broadcast();

  @override
  void dispose() {
    changeNotifier.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return new Column(
      children: <Widget>[
        new AnotherWidget(
          shouldTriggerChange: changeNotifier.stream,
        ),
        new RaisedButton(
          child: new Text("data"),
          onPressed: () => changeNotifier.sink.add(null),
        )
      ],
    );
  }
}

class AnotherWidget extends StatefulWidget {
  final Stream shouldTriggerChange;

  AnotherWidget({@required this.shouldTriggerChange});

  @override
  _AnotherWidgetState createState() => _AnotherWidgetState();
}

class _AnotherWidgetState extends State<AnotherWidget> {
  StreamSubscription streamSubscription;

  @override
  initState() {
    super.initState();
    streamSubscription = widget.shouldTriggerChange.listen((_) => someMethod());
  }

  @override
  didUpdateWidget(AnotherWidget old) {
    super.didUpdateWidget(old);
    // in case the stream instance changed, subscribe to the new one
    if (widget.shouldTriggerChange != old.shouldTriggerChange) {
      streamSubscription.cancel();
      streamSubscription = widget.shouldTriggerChange.listen((_) => someMethod());
    }
  }

  @override
  dispose() {
    super.dispose();
    streamSubscription.cancel();
  }

  void someMethod() {
    print('Hello World');
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}
class MySFWidget extends StatefulWidget {
  SFWidgetState currState;

  @override
  SFWidgetState createState(){
    currState = new SFWidgetState();
    return currState;
  };

}

class SFWidgetState extends State<MySFWidget> {

  int prop;

  void SomeMethod(){
    // DO Something
  }

  @override
  Widget build(BuildContext context) {
    return null;
  }

}