【问题标题】:Using a Switch() widget with GetX/Obx()使用带有 GetX/Obx() 的 Switch() 小部件
【发布时间】:2021-03-25 15:32:09
【问题描述】:

我又提出了一个问题:如何将 Switch() 小部件与 GetX/Obx() 一起使用? 在很多地方,我都读过 GetX/Obx 不需要 StatefullWidget。所以在我的应用程序中,我只使用 StatelessWidgets。问题是我无法让 Switch() 工作,因为 SetState() 在 StatelessWidget 中不可用。

有人可以帮忙吗? 谢谢你的好意。 A.KOTE

【问题讨论】:

    标签: flutter flutter-getx


    【解决方案1】:

    GetX + 开关

    这是在 StatelessWidget 中使用带有 Switch 小部件的 GetX 的复制/粘贴示例。

    import 'package:flutter/material.dart';
    import 'package:get/get.dart';
    
    /// GetX Controller for holding Switch's current value
    class SwitchX extends GetxController {
      RxBool on = false.obs; // our observable
    
      // swap true/false & save it to observable
      void toggle() => on.value = on.value ? false : true;
    }
    
    /// Stateless Page here
    class SwitchGetxPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        SwitchX sx = Get.put(SwitchX()); // Instantiate Get Controller, *in* build()
    
        return Scaffold(
          appBar: AppBar(
            title: Text('Switch Field'),
          ),
          body: SafeArea(
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  // Obx will rebuild Text & Switch when "on" observable changes
                  Obx(() => Text('Switch Setting: ${sx.on}')),
                  Obx(() => Switch(
                    onChanged: (val) => sx.toggle(), 
                    value: sx.on.value),
                  )
                ],
              ),
            ),
          ),
        );
      }
    }
    

    GetX + 状态

    使用 GetX,您不需要 StatefulWidgets,因为您在小部件之外保持“状态”,而在 GetxController 内部保持“状态”。

    在上面的示例中,RxBool on = false.obs 是您的应用程序的“状态”。在您的应用程序的整个生命周期中,它将是 truefalse

    Switch's 的值发生变化时,您需要重建任何小部件,将它们放入ObxGetXGetBuilder 并使用可观察变量。

    ObxGetX 将在其可观察到的变化时重建自己。 GetBuilder 需要您调用 update() 才能重建它。就像setState() 电话一样。

    为什么示例中有两个Obx

    为了让Obx/GetX 必须直接包装一个可观察变量,这一点非常明显。

    GetX 要求您直接在 Obx/GetX 中使用可观察变量,而不是像在孩子的孩子中那样进一步嵌套。

    例如,下面这个,会抛出一个错误:

    class SwitchGetxPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        SwitchX sx = Get.put(SwitchX());
    
        return Scaffold(
          appBar: AppBar(
            title: Text('Switch Field'),
          ),
          body: SafeArea(
            child: Center(
              child: Obx(() => MyTextSwitch(sx)), // don't do this, will explode
            ),
          ),
        );
      }
    }
    
    class MyTextSwitch extends StatelessWidget {
      final SwitchX sx;
    
      MyTextSwitch(this.sx);
    
      @override
      Widget build(BuildContext context) {
        return Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Switch Setting: ${sx.on}'),
            Switch(
                onChanged: (val) => sx.toggle(),
                value: sx.on.value)
          ],
        );
      }
    }
    

    下面的这个版本仍然可以,但没有在第一个示例中使用,因为它可能会导致不良习惯(例如重建不需要它的小部件)和上面示例中的错误。请记住,Obx/GetX 的子项中必须有一个 observable:

    class SwitchGetxPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        SwitchX sx = Get.put(SwitchX());
    
        return Scaffold(
          appBar: AppBar(
            title: Text('Switch Field'),
          ),
          body: SafeArea(
            child: Center(
              child: Obx( // still OK, but rebuilds Column unnecessarily
                () => Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Text('Switch Setting: ${sx.on}'),
                    Switch(
                        onChanged: (val) => sx.toggle(),
                        value: sx.on.value)
                  ],
                ),
              ),
            ),
          ),
        );
      }
    }
    

    【讨论】:

      【解决方案2】:

      对于简单的 Switch 状态切换,您不应使用控制器。控制器用于更复杂的业务逻辑实现,可以在屏幕之间共享。您可以使用Get 包中的ValueBuilder,它可以用更少的代码提供所需的结果。这是一个例子:

      Center(
                child: ValueBuilder<bool>(
                  initialValue: true,
                  builder: (isChecked, updateFn) => Switch(
                    value: isChecked,
                    onChanged: (newValue) => updateFn(newValue),
                  ),
                ),
              ),
      

      【讨论】:

      • 嗨,Sahoo,这没关系,它有效!!!非常感谢。是否可以对单选按钮使用相同的方法(我的意思是 radioListTile)?
      • 是的,只要您使用 GetX 包,任何需要具有本地状态的小部件都可以通过这种方式轻松完成。
      【解决方案3】:

      我可以给你一个例子,然后你可以在你的代码中实现。

      您可以使用 GetxController 来处理小部件状态。

      反例:

      class YourController extends GetxController {
        //The current value
        int counter = 0;
      
        void increment() {
          counter++;
          update(); // use update() to update counter variable on UI when increment be called
        }
      }
      

      然后在你的 statelessWidget 中你就可以收听了。

      class YourWidget extends StatelessWidget {
        @override
        Widget build(BuildContext context) {
          return Scaffold(
              body: Center(
            child: GetBuilder<YourController>(
              init: Controller(), // INIT IT ONLY THE FIRST TIME
              builder: (_) => Text(
                '${_.counter}',
              ),
            ),
          ));
        }
      }
      

      文档:https://github.com/jonataslaw/getx/blob/master/documentation/en_US/state_management.md#simple-state-manager

      如何更新值?

      向控制器添加一行

      class YourController extends GetxController {
            //New line added
            static YourController  get to => Get.find();
            int counter = 0;
      
            void increment() {
              counter++;
              update(); // use update() to update counter variable on UI when increment be called
            }
          }
      

      更新用户界面

      return Scaffold(
            // body: /*... */
            floatingActionButton: FloatingActionButton(
              child: Text('Hit'),
              onPressed: () {
                //Apply the logic to your Switch widget
                YourController.to.update();
              },
            ),
          );
        }
      

      【讨论】:

      • 您好罗兰多,非常感谢您的帮助。你的例子对我来说很清楚,我已经在我的代码中使用了相同的格式。我真正的问题是:我在 StatelessWidget 中有一个 Switch 小部件。我怎样才能获得它打开/关闭?我想当我使用 GetX/Obx() 时有可能。但是不知道怎么弄?
      猜你喜欢
      • 2022-01-02
      • 2021-06-07
      • 1970-01-01
      • 2021-11-11
      • 2021-09-15
      • 2021-10-07
      • 2021-11-07
      • 1970-01-01
      • 2022-11-04
      相关资源
      最近更新 更多