Flutter如何以编程方式调用自定义小部件中的方法?

标签 flutter dart widget custom-widgets

我是 Flutter 的新手,在尝试进行自定义切换时遇到了第一个障碍。我的开关在功能上应该与实际的 Switch 相同。从 Material 库来看,唯一的区别就是UI。

我正在使用 ValueNotifierValueListenableBuilder从另一个小部件更新开关值。这是我的代码的相关部分:

包含小部件

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

class _ParentWidgetState extends State<ParentWidget> {
    ValueNotifier _switchNotifier = ValueNotifier(false);

    @override
    Widget build(BuildContext context) {
        return Container(
            child: ValueListenableBuilder(
                valueListenable: _switchNotifier,
                builder: (context, switchValue, child) {
                    return _buildSwitch(switchValue);
                },
            ),
        );
    }

    Widget _buildSwitch(bool switchValue) {
        return CustomSwitch(
            key: Key(value.toString()),
            initValue: switchValue,
            onChanged: (value) {
                setState(() {
                    _switchNotifier.value = value;
                });
            },
        );
    }
}

改变开关值的小部件
class ChildWidget extends StatefulWidget {
    final ValueNotifier _switchNotifier;
    ChildWidget(this._switchNotifier);

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

class _ChildWidgetState extends State<ChildWidget> {
    @override
    Widget build(BuildContext context) {
        return Container(
            child: GestureDetector(
                onTap: () {
                    widget._switchNotifier.value = false;
                },
                child: Image(...),
            ),
        );
    }
}

自定义开关
class CustomSwitch extends StatefulWidget {
    final ValueChanged<bool> onChanged;
    final bool initValue;
    final Key key;

    const CustomSwitch({
        @required this.key,
        this.onChanged,
        this.initValue,
    });

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

class _CustomSwitchState extends State<CustomSwitch> {
    bool value;

    @override
    void initState() {
        value = widget.initValue;
        super.initState();
    }

    @override
    Widget build(BuildContext context) {
        // the switch/toggle is animated just like the Material Switch
        return TheSwitch(...);
    }

    _toggle() {
        setState(() {
            value = !value;
            widget.onChanged(value);
        });
    }
}

如果我调用 _toggle()来自 CustomSwitch开关会随着动画很好地切换(我使用 AnimatedPositioned 作为开关)。如果我只依赖用户输入,这很好用,但我还需要以编程方式切换开关,我觉得我错过了一些基本的东西,但我很难过。

我目前的理解是 CustomSwitch每次我将其值从 ChildWidget 更改时都会重建因为我将开关值用作 Key ,但是如何用动画很好地做到这一点,就好像我在调用 _toggle()建成后?

就像在 Java 中一样,您通常会执行 customSwitch.toggle() 之类的操作。 .

最佳答案

大多数 flutter 小部件使用 Controller 与外部小部件交互(TextFormField、ListView 等)。
对于您的问题,最简单的解决方案也是创建一个自定义 Controller 。
首先,您将创建一个 Controller 类,它将您的自定义小部件的状态作为参数。此类还将公开您的小部件的方法。它看起来像这样:

class CustomWidgetController{
  _CustomWidgetState _customWidgetState;

  void _addState(_CustomWidgetState customWidgetState){
    this._customWidgetState = customWidgetState;
  }

  /// Determine if the CustomWidgetController is attached to an instance
  /// of the CustomWidget (this property must return true before any other
  /// functions can be used)
  bool get isAttached => _customWidgetState != null;

  /// Here is the method you are exposing
  void toggle() {
    assert(isAttached, "CustomWidgetController must be attached to a CustomWidget");
    _customWidgetState.toggle();
  }
}
您需要接受 Custom Controller 作为 CustomWidget 中的参数,并将其传递给它的状态,如下所示:
class CustomSwitch extends StatefulWidget {
    final CustomWidgetController customWidgetController;
    final bool initValue;
    final Key key;

    const CustomSwitch({
        @required this.key,
        this.customWidgetController,
        this.initValue,
    });

    @override
    _CustomSwitchState createState() => _CustomSwitchState(customWidgetController, initValue);
}
在您的自定义类的状态中,您将使用我们创建的 addState 方法将您的类的状态分配给 Controller 。您可以像这样构造函数:
class _CustomSwitchState extends State<CustomSwitch> {
    final CustomWidgetController _customWidgetController;
    bool value;

    _CustomSwitchState(this._customWidgetController, this.value) {
    if (_customWidgetController != null)
        _customWidgetController._addState(this);
    }

    @override
    Widget build(BuildContext context) {
        // the switch/toggle is animated just like the Material Switch
        return TheSwitch(...);
    }

    toggle() {
        setState(() {
            value = !value;
        });
    }
}
现在,您可以使用父小部件中的 Controller 传递 Controller 并调用方法,如下所示:
  CustomWidgetController customWidgetController = new CustomWidgetController();

  @override
   Widget build(BuildContext context) {
        return CustomWidget(
            controller: customWidgetController,
            initValue: true
        );
    }
就是这个!现在您可以调用customWidgetController.toggle()在代码中的任何位置切换值!
这就是原生小部件让您与它们交互的方式。

关于Flutter如何以编程方式调用自定义小部件中的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59809686/

相关文章:

widget - 在 Spec 中添加一行会导致一列?

javascript - jQuery UI 对话框错误 : b ("<div></div>"). addClass ("ui-widget-overlay") 未定义

flutter - 无法更改 Dart 中的图像大小

flutter - 在 Flutter 中更新嵌套 CupertinoPageScaffold 中的 Scaffold-Properties

android-studio - 在 Android Studio 中为 Dart 启用 Rainbow Brackets

android - 是否有可能得到一个没有图标/只有文本的 bottomNavBar

android - 小部件 - 接收时 Intent 保持不变

android - 如何自定义 SearchDelegate(创建自定义搜索字段)

dart - 如何在 Flutter 中找出 URL 的有效性?

json - 解析JSON( map 列表)将返回null