Flutter - Stateful Widget не сохраняет состояние счетчика при переключении вкладок

Я учусь трепетать, я работаю с tabBars, и у меня возникла проблема с сохранением состояния. Ниже приведен небольшой рабочий пример моей проблемы. В основном, есть кнопка и счетчик состояния. Когда я нажимаю кнопку, я вижу правильное обновление текстового поля. Но когда я переключаюсь на другую вкладку и возвращаюсь, текстовое поле возвращается к нулю.

Я обнаружил, что если переместить следующую строку за пределы _CounterState, чтобы она была определена на верхнем уровне файла, то она работает правильно. Когда я переключаю вкладки, счетчик остается на правильное количество, когда я переключаю обратно

int _counter = 0;

Я не чувствую, что это подходящий способ сделать это, и все примеры, которые я видел, имеют переменную внутри класса. Кто-нибудь может дать мне какие-либо идеи? Зачем его сбрасывать, если он внутри класса? Я должен держать это вне класса? Ниже приведен упрощенный полный пример.

import 'package:flutter/material.dart';

void main() {
  runApp(new TabBarDemo());
}

class TabBarDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new DefaultTabController(
        length: 3,
        child: new Scaffold(
          appBar: new AppBar(
            bottom: new TabBar(
              tabs: [
                new Tab(icon: new Icon(Icons.directions_car)),
                new Tab(icon: new Icon(Icons.directions_transit)),
                new Tab(icon: new Icon(Icons.directions_bike)),
              ],
            ),
            title: new Text('Tabs Demo'),
          ),
          body: new TabBarView(
            children: [
              new Counter(),
              new Icon(Icons.directions_transit),
              new Icon(Icons.directions_bike),
            ],
          ),
        ),
      ),
    );
  }
}

class Counter extends StatefulWidget {
  @override
  _CounterState createState() => new _CounterState();
}

class _CounterState extends State<Counter> {
  int _counter = 0;

  void _increment() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Row(
      children: <Widget>[
        new RaisedButton(
          onPressed: _increment,
          child: new Text('Increment'),
        ),
        new Text('Count: $_counter'),
      ],
    );
  }
}

Ниже приведен пример со счетчиком, перемещенным за пределы класса.

import 'package:flutter/material.dart';

void main() {
  runApp(new TabBarDemo());
}

class TabBarDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new DefaultTabController(
        length: 3,
        child: new Scaffold(
          appBar: new AppBar(
            bottom: new TabBar(
              tabs: [
                new Tab(icon: new Icon(Icons.directions_car)),
                new Tab(icon: new Icon(Icons.directions_transit)),
                new Tab(icon: new Icon(Icons.directions_bike)),
              ],
            ),
            title: new Text('Tabs Demo'),
          ),
          body: new TabBarView(
            children: [
              new Counter(),
              new Icon(Icons.directions_transit),
              new Icon(Icons.directions_bike),
            ],
          ),
        ),
      ),
    );
  }
}

class Counter extends StatefulWidget {
  @override
  _CounterState createState() => new _CounterState();
}

int _counter = 0; //<-- MOVED OUTSIDE THE _CounterState CLASS
class _CounterState extends State<Counter> {


  void _increment() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Row(
      children: <Widget>[
        new RaisedButton(
          onPressed: _increment,
          child: new Text('Increment'),
        ),
        new Text('Count: $_counter'),
      ],
    );
  }
}

1 ответ

Решение

Как _CounterState виджет строится каждый раз, когда вы идете в данный TabView вам нужно поставить _counter переменная в классе конфигурации состояния (Counter).

class Counter extends StatefulWidget {
  int _counter = 0;
  @override
  _CounterState createState() => new _CounterState();
}

class _CounterState extends State<Counter> {
  void _increment() {
    setState(() {
      widget._counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Row(
      children: <Widget>[
        new RaisedButton(
          onPressed: _increment,
          child: new Text('Increment'),
        ),
        new Text('Count: ${widget._counter}'),
      ],
    );
  }
}

Как я использовал одно решение AutomaticKeepAliveClientMixin

Вам нужно использовать этот миксин с вашим классом состояния StateFullWidget.

вам нужно передать истинный к wantKeepAlive метод получения.

class SampleWidget extends StatefulWidget {
  @override
  _SampleWidgetState createState() => _SampleWidgetState();
}

class _SampleWidgetState extends State<SampleWidget> with AutomaticKeepAliveClientMixin{
  @override
  Widget build(BuildContext context) {
    return Container();
  }

  @override
  // TODO: implement wantKeepAlive
  bool get wantKeepAlive => true;
}

Это сохранит ваше состояние и остановит воссоздание вашего виджета. Я использовал его с Tabbar и PageView, и он работает нормально.

Поместите переменную в этот statefulwidget и затем каждый раз вызывайте ее как "widget.variable_name"

Другие вопросы по тегам