简体   繁体   中英

How to perserve toggle switch state when changing tabs for flutter?

I'm building three pages of alarms (stored in different lists) that I have displayed via a Scaffold and TabViewer. Each alarm is stored as a row with a toggle switch to enable it. The rows for each page are stored as a List. Despite making sure to use set state when changing values and even trying to assign unique keys nothing I do seems to preserve the state of the switches when I changed tabs.

This is my first time coding in Flutter/Dart or designing an app for mobile in general. As such I'm still learning about some basic features of this language.

I've tried adding keys to everything using Uniquekey() to generate up keys didn't work so I've removed them. I've made sure all variable changes are inside set state functions. I've tried to store the variable inside the immutable super class of AlarmToggle which is both ill-advised and doesn't work anyways.

I haven't tired using PageStorageKey as I'm not sure how they'd be implemented in my code but I feel this is likely the only solution.

class Alarms {
  List<Widget> allAlarms = []; // Store all alarms for the object

  buildAlarm(
      GlobalKey<ScaffoldState>
          pageKey,
      [int hour,
      int minute,
      List<bool> alarmDaysOfWeek]) {

    TimeOfDay alarmTime = TimeOfDay(hour: hour, minute: minute);
    AlarmRow _newAlarm = new AlarmRow(UniqueKey(), alarmTime, alarmDaysOfWeek);
    allAlarms.add(_newAlarm);
  }
  void removeAlarm(GlobalKey<ScaffoldState> pageKey) {allAlarms.removeLast();}}

class AlarmRow extends StatefulWidget {
  final TimeOfDay _alarmTime;
  final List<bool> _alarmDaysofWeek;
  final UniqueKey key;
  AlarmRow(this.key, this._alarmTime, this._alarmDaysofWeek);
  AlarmRowState createState() => new AlarmRowState();
}

class AlarmRowState extends State<AlarmRow> {
  bool _alarmIsActive;

  AlarmRowState(){_alarmIsActive = _alarmIsActive ?? false;}

  void toggleChanged(bool state) {this.setState(() {_alarmIsActive = state;});}

  @override
  Widget build(BuildContext context) {
    return new Container(
      child: Row(
        children: <Widget>[
          new AlarmIcon(_alarmIsActive),
          new Column(
            children: <Widget>[
              new AlarmTime(widget._alarmTime),
              new AlarmWeekly(widget._alarmDaysofWeek),
            ],
          ),
          new AlarmToggle(
            _alarmIsActive,
            () => toggleChanged(!_alarmIsActive),
          ),
        ],
      ),
    );
  } // Build
} // Class

No matter what I seem to try the _alarmIsActive variable in AlarmRow() gets reset to null each time the tab is changed. I'm trying to preserve its state when changing pages.

The solution is as jdv stated to use AutomaticKeepAliveClientMixin , it's not hard to use but I figured I'd include the instruction that I found after searching here in case anyone searches and finds this and doesn't know automatically how to implement it like myself.

class AlarmRowState extends State<AlarmRow> with AutomaticKeepAliveClientMixin {
    @override bool get wantKeepAlive => true;

It's implemented in the state class with any modifiable variables you want to preserve. The 'with' after the 'extends' adds a Mixin which is a sort of class inheritance. Finally, it requires you to set the 'wantKeepAlive' to true and it compiles and state is no longer lost while the widget is not being rendered.

Why a stateful widget loses state while it's not rendered is something I'm still searching for. But at least I have a solution.

I hope this will help you @Ender ! check for this code, you can create a Global shared preference and use it, as shown below:-

class AlarmRow extends StatefulWidget {

  @override
  State<StatefulWidget> createState() => new _AlarmRowState();
}

class _AlarmRowState extends State<AlarmRow>{
  bool alarmIsActive;
  @override
  void initState() {
    alarmIsActive = Global.shared.alarmIsActive;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    ....
.....
....
....
      body: new Container(
        child:  Switch(
          value: alarmIsActive,
          onChanged: (bool isEnabled) {

            setState(() {
             alarmIsActive = isEnabled;
             Global.shared.alarmIsActive = isEnabled;
             isEnabled =!isEnabled;
            });
          },
         .....
......
        ),
      ),
    );
  }
}
class Global{
  static final shared =Global();
  bool alarmIsActive = false;
}

Switch enabled and will maintain its state

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM