Flutter 如何设置下拉按钮';以编程方式实现s值?

Flutter 如何设置下拉按钮';以编程方式实现s值?,flutter,Flutter,例如,为了设置TextFormField中的文本,我可以使用TextEditingController: textEditingController = TextEditingController() ... TextFormField( controller: textEditingController ); ... textEditingController.text = 'my text'; // This is where I can set the text in the Te

例如,为了设置
TextFormField
中的文本,我可以使用
TextEditingController

textEditingController = TextEditingController()
...

TextFormField(
  controller: textEditingController
);
...

textEditingController.text = 'my text'; // This is where I can set the text in the TextFormField

是否有类似的方法以编程方式在
下拉按钮中设置选择?据我所知,仅仅在
下拉按钮中设置
字段是不够的,因为如果不从包装
状态
对象调用
设置状态
,就无法应用更改,此处似乎没有快捷方式,必须调用
设置状态
,以反映
下拉按钮
所选值中的更改。问题是,
setState
是受保护的,所以我需要遍历一些循环,以确保在需要时调用它。我最终实现了一个通知程序,
DropdownButton
的状态将是它的侦听器。大致如下:

class MyStatefulWidget extends StatefulWidget {

  final _valueNotifier = ValueNotifier<String>(null);

  @override
  State<StatefulWidget> createState() => MyState(_valueNotifier);

  // This exposes the ability to change the DropdownButtons's value
  void setDropdownValue(String value) {
    // This will notify the state and will eventually call setState
    _valueNotifier.value = value;
  }
}

class MyState extends State<MyStatefulWidget> {
  String _selection;

  MyState(ValueNotifier<String> valueNotifier) {
    valueNotifier.addListener(() {
      setState(() {
        _selection = valueNotifier.value;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return DropdownButton<String>(
      items: [
        DropdownMenuItem<String>(
          value: "1",
          child: Text(
            "1",
          ),
        ),
        DropdownMenuItem<String>(
          value: "2",
          child: Text(
            "2",
          ),
        )
      ],
      onChanged: (value) {
        setState(() {
          _selection = value;
        });
      },
      value: _selection,
    );
  }
}
类MyStatefulWidget扩展StatefulWidget{
最终_valueNotifier=valueNotifier(null);
@凌驾
State createState()=>MyState(_valueNotifier);
//这暴露了更改DropdownButtons值的能力
void setDropdownValue(字符串值){
//这将通知状态,并最终调用setState
_valueNotifier.value=值;
}
}
类MyState扩展状态{
字符串选择;
MyState(ValueNotifier ValueNotifier){
valueNotifier.addListener((){
设置状态(){
_选择=valueNotifier.value;
});
});
}
@凌驾
小部件构建(构建上下文){
返回下拉按钮(
项目:[
下拉菜单项(
值:“1”,
子:文本(
"1",
),
),
下拉菜单项(
值:“2”,
子:文本(
"2",
),
)
],
一旦更改:(值){
设置状态(){
_选择=价值;
});
},
值:_选择,
);
}
}

如果将逻辑与用户界面分离,并通过用户界面监听的流传递事件,则可以使用setState四处走动,并且逻辑更易于使用

StreamBuilder是一个很棒的小部件,如果您习惯了使用它,它可以大大简化ui代码。本质上,每次新值通过流时,构建器函数都会重新运行,并且可以在snapshot.data中找到放入流中的任何内容,如新的下拉按钮值

下面是一个例子:

在您的ui中,您可以像这样构建下拉按钮:

      StreamBuilder<String>(
        stream: logicClass.dropdownValueStream,
        builder: (context, snapshot) {
          return DropdownButton(
            items: logicClass.menuItems,
            onChanged: logicClass.selectItem,
            value: snapshot.data,
          );
      })
  StreamController<String> _dropDownController = StreamController<String>();
  Stream<String> get dropdownValueStream => _dropDownController.stream;
  Function get selectItem => _dropDownController.sink.add;
SimpleDropdownButton(
  values: _values,
  itemBuilder: (value) => Text(value),
  controller: _controller,
  onChanged: (value) => print(_controller.value),
)
StreamBuilder(
流:logicClass.dropdownValueStream,
生成器:(上下文,快照){
返回下拉按钮(
项目:logicClass.menuItems,
一旦更改:logicClass.selectItem,
值:snapshot.data,
);
})
在logic类中,您将构建如下流:

      StreamBuilder<String>(
        stream: logicClass.dropdownValueStream,
        builder: (context, snapshot) {
          return DropdownButton(
            items: logicClass.menuItems,
            onChanged: logicClass.selectItem,
            value: snapshot.data,
          );
      })
  StreamController<String> _dropDownController = StreamController<String>();
  Stream<String> get dropdownValueStream => _dropDownController.stream;
  Function get selectItem => _dropDownController.sink.add;
SimpleDropdownButton(
  values: _values,
  itemBuilder: (value) => Text(value),
  controller: _controller,
  onChanged: (value) => print(_controller.value),
)
StreamController\u dropDownController=StreamController();
Stream get dropdownValueStream=>\u dropDownController.Stream;
函数get-selectItem=>\u-dropDownController.sink.add;

最后,如果您想对这些数据执行任何操作,可以在数据通过流时将其存储在逻辑类中。这本质上是UI逻辑与业务逻辑或Bloc模式的分离

我创建了一个简化的
下拉按钮
来使用控制器,它可以这样使用:

      StreamBuilder<String>(
        stream: logicClass.dropdownValueStream,
        builder: (context, snapshot) {
          return DropdownButton(
            items: logicClass.menuItems,
            onChanged: logicClass.selectItem,
            value: snapshot.data,
          );
      })
  StreamController<String> _dropDownController = StreamController<String>();
  Stream<String> get dropdownValueStream => _dropDownController.stream;
  Function get selectItem => _dropDownController.sink.add;
SimpleDropdownButton(
  values: _values,
  itemBuilder: (value) => Text(value),
  controller: _controller,
  onChanged: (value) => print(_controller.value),
)
基本上,
SimpleDropdownButton
包装了一个
DropdownButton
,并根据接收到的值列表和您希望显示这些值的方式来处理其
DropdownItems
的创建

如果不设置控制器,则使用
setState()
SimpleDropdownButton
将像处理
DropdownButton
一样处理所选值

如果确实设置了控制器,则
SimpleDropdownButton
开始侦听控制器,以了解何时调用
setState()
更新所选值。因此,如果有人选择一个项目(
onChanged
),那么
SimpleDropdownButton
将不会调用
setState()
,而是将新值设置到控制器,控制器将通知侦听器,其中一个侦听器是
SimpleDropdownButton
,他将调用
setState()
更新所选值。这样,如果您为控制器设置了一个新值,
SimpleDropdownButton
将收到通知。此外,由于值始终存储在控制器上,因此可以随时访问


这是实现,您可能希望将更多参数传递到
下拉按钮

class SimpleDropdownButton<T> extends StatefulWidget {
  final List<T> values;
  final Widget Function(T value) itemBuilder;
  final SimpleDropdownButtonController<T> controller;
  final ValueChanged onChanged;

  SimpleDropdownButton(
      {this.controller,
      @required this.values,
      @required this.itemBuilder,
      this.onChanged});

  @override
  _SimpleDropdownButtonState<T> createState() =>
      _SimpleDropdownButtonState<T>();
}

class _SimpleDropdownButtonState<T> extends State<SimpleDropdownButton<T>> {
  T _value;

  @override
  void initState() {
    super.initState();
    if (widget.controller != null) {
      _value = widget.controller.value;
      widget.controller.addListener(() => setState(() {
            _value = widget.controller.value;
          }));
    }
  }

  @override
  void dispose() {
    widget.controller?.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return DropdownButton(
      value: _value,
      items: widget.values
          .map((value) => DropdownMenuItem(
                value: value,
                child: widget.itemBuilder(value),
              ))
          .toList(),
      onChanged: (value) {
        if (widget.controller != null) {
          widget.controller.value = value;
        } else {
          setState(() {
            _value = value;
          });
        }
        widget.onChanged?.call(value);
      },
    );
  }
}

class SimpleDropdownButtonController<T> {
  List<VoidCallback> _listeners = [];
  T _value;

  SimpleDropdownButtonController([this._value]);

  get value => _value;

  set value(T value) {
    _value = value;
    _listeners?.forEach((listener) => listener());
  }

  void addListener(VoidCallback listener) => _listeners.add(listener);

  void close() => _listeners?.clear();
}

这是更改
下拉按钮
值的唯一方法,您必须使用新值调用
setState