Флажки приложения Flutter перестают переключать состояние при изменении страницы - PullRequest
0 голосов
/ 21 июня 2020

У меня проблема с параметром класса, который обычно не полностью инициализируется к моменту визуализации страницы. В частности, это происходит с флажками. Обычно я не могу переключить их состояние при нажатии, по-видимому, из-за того, что значения списка параметров подчеркивания пусты. По крайней мере, это то, что я вижу при отладке. Вот код простого приложения, которое воспроизводит ошибочное поведение (флажки перестают реагировать на нажатия после нажатия «Назад» или «Далее»):

import 'package:flutter/material.dart';

class Value {
  String _id;
  String title;
  
  Value(id) {
    _id = id;
  }
}

class Story {
  Map<Value, bool> _valuesSelection = {};
  State _state;
  
  Story(state) {
    _state = state;
  }
  
  void addValue(Value value, {bool enabled = false}) {
    _valuesSelection.putIfAbsent(value, () => enabled);
  }
  
  bool getValueState(Value value) {
    return _valuesSelection[value];
  }
  
  void toggleValue(Value value) {
    _valuesSelection[value] = !_valuesSelection[value];
  }
  
  void enableValue(Value value) {
    _valuesSelection[value] = true;
  }
  
  void disableValue(Value value) {
    _valuesSelection[value] = false;
  }
  
  Value getValueById(String id) {
    return _valuesSelection.keys.where((element) => element._id == id).toList()[0];
  }
  
  List<Value> getAllValues() {
    return _valuesSelection.keys.toList();
  }

  Widget buttons(BuildContext context) {
  
    Widget previousNextButtons = Row(children: <Widget>[
      Expanded(child: Container(
        padding: EdgeInsets.all(20),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            Column(
              children: <Widget>[
                FlatButton(
                  onPressed: () {
                    var previousStoryPageWidget = StoryStartPage(1);
                    Future( () {
                      Navigator.of(context).push(
                        MaterialPageRoute(builder: (BuildContext context) => previousStoryPageWidget )
                      );
                    });
                  },
                  child: Container(
                    height: 50,
                    width: 150,
                    decoration: BoxDecoration(
                      color: Colors.red,
                      borderRadius: BorderRadius.all(Radius.circular(35.0))),
                    child: Column(
                      children: <Widget> [
                        Expanded(
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: <Widget>[
                              Text("Previous", style: TextStyle(color: Colors.white, fontSize: 16), textAlign: TextAlign.center),
                            ]
                          )
                        )
                      ],
                    )
                  )
                )
              ],
            ),
            Column(
              children: <Widget>[
                FlatButton(
                  onPressed: () {// if OK button is active
                    var nextStoryPageWidget = StoryStartPage(1);
                    Future( () {
                      Navigator.of(context).push(
                        MaterialPageRoute(builder: (BuildContext context) => nextStoryPageWidget )
                      );
                    });
                  },
                  child: Container(
                    height: 50,
                    width: 150,
                    decoration: BoxDecoration(
                      color: Colors.green,
                      borderRadius: BorderRadius.all(Radius.circular(35.0))),
                    child: Column(
                      children: <Widget> [
                        Expanded(
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: <Widget>[
                              Text(
                                "Next",
                                style: TextStyle(
                                  color: Colors.white,
                                  fontSize: 16
                                ),
                                textAlign: TextAlign.center),
                            ]
                          )
                        )
                      ],
                    )
                  )
                )
              ],
            )
          ],
        )
      ))
    ]
    );
    
    return Container(
      height: 140,
      child: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          previousNextButtons,
        ])
    );
  }


  Widget render(BuildContext context) {
    final controller = ScrollController();
    return Column(
      children: <Widget>[
        Scrollbar(
          isAlwaysShown: true,
          controller: controller,
          child: ListView(
            padding: EdgeInsets.zero,
            scrollDirection: Axis.vertical,
            shrinkWrap: true,
            controller: controller,
            children: List.generate(
              _valuesSelection.length,
                (index) => ListTile(
                title: CheckboxListTile(
                  title: Text(_valuesSelection.keys.toList()[index].title),
                  value: getValueState(_valuesSelection.keys.toList()[index]),
                  onChanged: (newValue) {
                    _state.setState(() {
                      toggleValue(_valuesSelection.keys.toList()[index]);
                    });
                  },
                  controlAffinity: ListTileControlAffinity.leading,
                ),
              ),
            )
          )
        ),
        buttons(context)
      ],
    );
  }
}

class Story1 extends Story {
  Story1(state) : super(state) {
    
    Value value1 = Value("1");
    value1.title = "Value One";
    this.addValue(value1);
    
    Value value2 = Value("2");
    value2.title = "Value Two";
    this.addValue(value2);
    
    Value value3 = Value("3");
    value2.title = "Value Three";
    this.addValue(value2);
    
    Value value4 = Value("4");
    value4.title = "Value Four";
    this.addValue(value4);
    
    Value value5 = Value("5");
    value5.title = "Value Five";
    this.addValue(value5);
    
  }
}

class Story2 extends Story {
  Story2(state) : super(state) {
    
    Value value1 = Value("1");
    value1.title = "Value One";
    this.addValue(value1);
    
    Value value2 = Value("2");
    value2.title = "Value Two";
    this.addValue(value2);
    
    Value value3 = Value("3");
    value2.title = "Value Three";
    this.addValue(value2);
    
  }
}

class StoryStartPage extends StatefulWidget {
  
  int _storyNumber = 1;
  
  StoryStartPage(this._storyNumber);
  
  @override
  _StoryStartState createState() => _StoryStartState(_storyNumber);
}

class _StoryStartState extends State<StoryStartPage> {
  
  int storyNumber = 1;
  
  Story story;
  
  _StoryStartState(this.storyNumber);
  
  @override
  void initState() {
    super.initState();
    if(story == null) {
      story = StoryFactory(this).getStory(storyNumber);
    }
  }
  
  @override
  Widget build(BuildContext context) {
    if(story != null) {
      return SafeArea(child: Scaffold(
        body: story.render(context))
      );
    } else {
      return Scaffold();
    }
  }
}

class StoryFactory {
  
  static final StoryFactory _singleton = new StoryFactory._internal(_state);
  
  Map<String, Story> allStories = {};
  
  static State _state;
  
  factory StoryFactory(state) {
    _state = state;
    return _singleton;
  }
  
  StoryFactory._internal(state) {
    allStories.addAll({"1": Story1(state)});
    allStories.addAll({"2": Story2(state)});
  }
  
  Story getStory(storyNumber) {
    return allStories[storyNumber.toString()];
  }
  
  List<Story> getAllStories() {
    return allStories.values.toList();
  }
  
}

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  
  StatefulWidget _homePage = StoryStartPage(1);
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'MyApp',
      theme: ThemeData.dark(),
      home: _homePage,
    );
  }
  
  MyApp();
}

1 Ответ

1 голос
/ 21 июня 2020

В основном проблема здесь в том, что вы пытаетесь все перестроить. Когда они говорят: все является виджетом : доверяйте им.

Я пытаюсь сказать, что ваша «История» должна быть виджетом. Если вы сделаете это так, он унаследует множество вещей, включая управление состоянием, которое включает c StatefullWidget.

Я обновил ваш код до рабочего примера. Не стесняйтесь спрашивать, есть ли что-то, чего вы не получаете.

import 'package:flutter/material.dart';

class Value {
  String _id;
  String title;

  Value(id) {
    _id = id;
  }
}

class Story extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _StoryState();
  Map<Value, bool> _valuesSelection = {};

  void addValue(Value value, {bool enabled = false}) {
    _valuesSelection.putIfAbsent(value, () => enabled);
  }

  bool getValueState(Value value) {
    return _valuesSelection[value];
  }

  void toggleValue(Value value) {
    _valuesSelection[value] = !_valuesSelection[value];
  }

  void enableValue(Value value) {
    _valuesSelection[value] = true;
  }

  void disableValue(Value value) {
    _valuesSelection[value] = false;
  }

  Value getValueById(String id) {
    return _valuesSelection.keys.where((element) => element._id == id).toList()[0];
  }

  List<Value> getAllValues() {
    return _valuesSelection.keys.toList();
  }
}

class _StoryState extends State<Story> {
  Widget buttons(BuildContext context) {
    Widget previousNextButtons = Row(children: <Widget>[
      Expanded(
          child: Container(
              padding: EdgeInsets.all(20),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: <Widget>[
                  Column(
                    children: <Widget>[
                      FlatButton(
                          onPressed: () {
                            var previousStoryPageWidget = StoryStartPage(1);
                            Future(() {
                              Navigator.of(context).push(MaterialPageRoute(
                                  builder: (BuildContext context) => previousStoryPageWidget));
                            });
                          },
                          child: Container(
                              height: 50,
                              width: 150,
                              decoration: BoxDecoration(
                                  color: Colors.red,
                                  borderRadius: BorderRadius.all(Radius.circular(35.0))),
                              child: Column(
                                children: <Widget>[
                                  Expanded(
                                      child: Row(
                                          mainAxisAlignment: MainAxisAlignment.center,
                                          children: <Widget>[
                                        Text("Previous",
                                            style:
                                                TextStyle(color: Colors.white, fontSize: 16),
                                            textAlign: TextAlign.center),
                                      ]))
                                ],
                              )))
                    ],
                  ),
                  Column(
                    children: <Widget>[
                      FlatButton(
                          onPressed: () {
                            // if OK button is active
                            var nextStoryPageWidget = StoryStartPage(1);
                            Future(() {
                              Navigator.of(context).push(MaterialPageRoute(
                                  builder: (BuildContext context) => nextStoryPageWidget));
                            });
                          },
                          child: Container(
                              height: 50,
                              width: 150,
                              decoration: BoxDecoration(
                                  color: Colors.green,
                                  borderRadius: BorderRadius.all(Radius.circular(35.0))),
                              child: Column(
                                children: <Widget>[
                                  Expanded(
                                      child: Row(
                                          mainAxisAlignment: MainAxisAlignment.center,
                                          children: <Widget>[
                                        Text("Next",
                                            style:
                                                TextStyle(color: Colors.white, fontSize: 16),
                                            textAlign: TextAlign.center),
                                      ]))
                                ],
                              )))
                    ],
                  )
                ],
              )))
    ]);

    return Container(
        height: 140,
        child: Column(mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[
          previousNextButtons,
        ]));
  }

  Widget build(BuildContext context) {
    final controller = ScrollController();
    return Column(
      children: <Widget>[
        Scrollbar(
            isAlwaysShown: true,
            controller: controller,
            child: ListView(
                padding: EdgeInsets.zero,
                scrollDirection: Axis.vertical,
                shrinkWrap: true,
                controller: controller,
                children: List.generate(
                  widget._valuesSelection.length,
                  (index) => ListTile(
                    title: CheckboxListTile(
                      title: Text(widget._valuesSelection.keys.toList()[index].title),
                      value:
                          widget.getValueState(widget._valuesSelection.keys.toList()[index]),
                      onChanged: (newValue) {
                        setState(() {
                          widget.toggleValue(widget._valuesSelection.keys.toList()[index]);
                        });
                      },
                      controlAffinity: ListTileControlAffinity.leading,
                    ),
                  ),
                ))),
        buttons(context)
      ],
    );
  }
}

class Story1 extends Story {
  Story1(state) : super() {
    Value value1 = Value("1");
    value1.title = "Value One";
    this.addValue(value1);

    Value value2 = Value("2");
    value2.title = "Value Two";
    this.addValue(value2);

    Value value3 = Value("3");
    value2.title = "Value Three";
    this.addValue(value2);

    Value value4 = Value("4");
    value4.title = "Value Four";
    this.addValue(value4);

    Value value5 = Value("5");
    value5.title = "Value Five";
    this.addValue(value5);
  }
}

class Story2 extends Story {
  Story2(state) : super() {
    Value value1 = Value("1");
    value1.title = "Value One";
    this.addValue(value1);

    Value value2 = Value("2");
    value2.title = "Value Two";
    this.addValue(value2);

    Value value3 = Value("3");
    value2.title = "Value Three";
    this.addValue(value2);
  }
}

class StoryStartPage extends StatefulWidget {
  int _storyNumber = 1;

  StoryStartPage(this._storyNumber);

  @override
  _StoryStartState createState() => _StoryStartState(_storyNumber);
}

class _StoryStartState extends State<StoryStartPage> {
  int storyNumber = 1;

  Story story;

  _StoryStartState(this.storyNumber);

  @override
  void initState() {
    super.initState();
    if (story == null) {
      story = StoryFactory(this).getStory(storyNumber);
    }
  }

  @override
  Widget build(BuildContext context) {
    if (story != null) {
      return SafeArea(child: Scaffold(body: story));
    } else {
      return Scaffold();
    }
  }
}

class StoryFactory {
  static final StoryFactory _singleton = new StoryFactory._internal(_state);

  Map<String, Story> allStories = {};

  static State _state;

  factory StoryFactory(state) {
    _state = state;
    return _singleton;
  }

  StoryFactory._internal(state) {
    allStories.addAll({"1": Story1(state)});
    allStories.addAll({"2": Story2(state)});
  }

  Story getStory(storyNumber) {
    return allStories[storyNumber.toString()];
  }

  List<Story> getAllStories() {
    return allStories.values.toList();
  }
}

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  StatefulWidget _homePage = StoryStartPage(1);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'MyApp',
      theme: ThemeData.dark(),
      home: _homePage,
    );
  }

  MyApp();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...