Использование виджета Switch () с GetX / Obx ()

Я снова задаюсь вопросом: как использовать виджет Switch () с GetX / Obx ()? Во многих местах я читал, что с GetX / Obx нет необходимости в StatefullWidget. Поэтому в своем приложении я использую только StatelessWidgets. Проблема в том, что я не могу заставить Switch () работать, потому что SetState () не может использоваться в StatelessWidget.

Кто-нибудь может помочь, пожалуйста? Благодарю за доброту. А.КОТЕ


person user3321083    schedule 15.12.2020    source источник


Ответы (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();
        },
      ),
    );
  }
person Rolando Garcia    schedule 15.12.2020
comment
Привет, Роландо, Большое спасибо за вашу помощь. Ваш пример мне понятен, и я уже использую тот же формат в своем коде. Моя настоящая проблема: у меня есть виджет Switch в StatelessWidget. Как я могу получить его включение / выключение? Думаю, это будет возможно, когда я воспользуюсь GetX / Obx (). Но я не знаю как? - person user3321083; 15.12.2020
comment
Вы можете поделиться своим кодом? - person Rolando Garcia; 16.12.2020

Для простого переключения состояния Switch вы не должны использовать контроллер. Контроллер предназначен для более сложной реализации бизнес-логики, которую можно использовать на экранах. Вы можете использовать ValueBuilder из Get пакета, который может дать желаемый результат с меньшим количеством кода. Вот пример:

Center(
          child: ValueBuilder<bool>(
            initialValue: true,
            builder: (isChecked, updateFn) => Switch(
              value: isChecked,
              onChanged: (newValue) => updateFn(newValue),
            ),
          ),
        ),
person Sumit Sahoo    schedule 16.12.2020
comment
Привет, Sahoo, это нормально, это работает !!! Спасибо большое. Можно ли использовать тот же метод для радио-кнопок (я имею в виду radioListTile)? - person user3321083; 18.12.2020
comment
Да, любой виджет, для которого требуется локальное состояние, может быть легко выполнен таким образом, если вы используете пакет GetX. - person Sumit Sahoo; 18.12.2020

GetX + Switch

Вот пример копирования / вставки использования GetX с виджетом Switch внутри StatelessWidget.

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 + State

С GetX вам не нужно StatefulWidgets, потому что вы храните состояние вне виджетов и внутри GetxController.

В приведенном выше примере RxBool on = false.obs - это состояние вашего приложения. Это будет true или false на протяжении всего срока службы вашего приложения.

Когда значение Switch's изменяется, любые виджеты, которые вам нужно перестроить, помещают в Obx, GetX или GetBuilder и используют наблюдаемую переменную.

Obx, GetX будут восстанавливать себя всякий раз, когда их наблюдаемые изменения. 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 должен иметь наблюдаемое в своем дочернем элементе:

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)
              ],
            ),
          ),
        ),
      ),
    );
  }
}
person Baker    schedule 05.04.2021