#flutter #flutter-getx
#flutter #flutter-getx
Вопрос:
Я возвращаюсь к вопросу: как я могу использовать виджет Switch () с getX / Obx ()? Во многих местах я читал, что с getX / Obx нет необходимости в StatefullWidget. Итак, в моем приложении я использую только StatelessWidgets. Проблема в том, что я не могу заставить Switch() работать, потому что setState() недоступен в StatelessWidget.
Может кто-нибудь помочь, пожалуйста? Спасибо за вашу доброту. А.КОТЭ
Ответ №1:
getX Переключатель
Вот пример копирования / вставки использования 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 amp; 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 amp; Switch when "on" observable changes
Obx(() => Text('Switch Setting: ${sx.on}')),
Obx(() => Switch(
onChanged: (val) => sx.toggle(),
value: sx.on.value),
)
],
),
),
),
);
}
}
getX Состояние
С getX вам не нужно StatefulWidgets
, потому что вы держите «состояние» вне виджетов и «внутри» a 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
в его дочернем элементе должен быть 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:
Для простого переключения состояния переключателя вы не должны использовать контроллер. Контроллер предназначен для более сложной реализации бизнес-логики, которая может быть разделена между экранами. Вы можете использовать ValueBuilder
из Get
пакета, который может дать желаемый результат с меньшим количеством кода. Вот пример :
Center(
child: ValueBuilder<bool>(
initialValue: true,
builder: (isChecked, updateFn) => Switch(
value: isChecked,
onChanged: (newValue) => updateFn(newValue),
),
),
),
Комментарии:
1. Привет, все в порядке, это работает!!! Большое спасибо. Можно ли использовать тот же метод для переключателей (я имею в виду radioListTile)?
2. Да, любой виджет, для которого требуется локальное состояние, можно легко выполнить таким образом, если вы используете пакет getX.
3. выдает ошибку:
Expected a value of type '(bool?, (bool?) => void) => Widget', but got one of type '(bool, (bool) => void) => Switch'
4. Ответ был до того, как был введен нулевой сейф, но теперь его необходимо настроить, чтобы он был нулевым.
Ответ №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}',
),
),
));
}
}
Как вы можете обновить значение?
Добавьте строку в свой контроллер
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();
},
),
);
}
Комментарии:
1. Привет, Роландо, большое спасибо за вашу помощь. Ваш пример мне понятен, и я уже использую тот же формат в своем коде. Моя настоящая проблема заключается в следующем: у меня есть виджет переключения в StatelessWidget. Как я могу добиться его включения / выключения? Я думаю, это будет возможно, когда я использую getX / Obx(). Но я не знаю, как это сделать?