Flutter: setState (() {} не может перерисовать значение DropdownButton - PullRequest
0 голосов
/ 29 мая 2020

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

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

На основании того, что я уже узнал, я подозреваю, что проблема связана с сохранением состояния моего виджета или его отсутствием. Я нашел несколько похожих вопросов, в которых предлагалось использовать StatefulBuilder, однако, когда я попытался реализовать его, в коде были ошибки или дублировалась вся моя группа ListTile. Я также видел предложения о создании виджета с отслеживанием состояния, но инструкции были слишком расплывчаты, чтобы я мог их выполнить и реализовать без ошибок. Я включаю фрагменты кода ниже, я не решаюсь вставить все это целиком, потому что на данный момент приложение содержит почти 2000 строк. Пожалуйста, дайте мне знать, если потребуется дополнительная информация или код. это код проблемы c, см. ниже код в контексте.

        DropdownButton(
          value: skillChoice,
          items: listDrop,
          hint: Text("Choose Skill"),
          onChanged: (value) {
            setState(() {
              skillChoice = value;
            });
          },
        ),
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Hunters Guild',
      theme: ThemeData(
        primaryColor: Colors.grey,
      ),
      home: Main(),
    );
  }
}
final List<Combatant> _combatants = List<Combatant>(); 
//combatant is a class that holds stats like HP which may change during a battle
//they also have a Fighter and a Monster and one of those will be null and the other useful
//depending if faction = "good" or "evil
//I am aware that this may not be the most elegant implementation but that is a problem for another day.

class MainState extends State<Main> {
  final List<Fighter> _squad = List<Fighter>(); 
//Fighter is a class which stores info like HP, name, skills, etc for game character,
//this List is populated in the page previous to _fight 
//where the user picks which characters they are using in a given battle
void _fight(Quest theQuest){
    for(Fighter guy in _squad){
      _combatants.add(Combatant("good", guy, null));
    }
    _combatants.add(Combatant("evil", null, theQuest.boss)); 
//quests are a class which store a boss Monster, later on I will add other things like rewards and prerequisites
final tiles = _combatants.map((Combatant comba){ //this structure is from the build your first app codelab
      List<DropdownMenuItem<String>> listDrop = [];
      String skillChoice = null;
      if (comba.faction == "good"){
        for (Skill skill in comba.guy.skills){
          listDrop.add((DropdownMenuItem(child: Text(skill.name), value: skill.name)));
        }
      }
      else if (comba.faction == "evil"){
        for (Skill skill in comba.boss.skills){
          listDrop.add((DropdownMenuItem(child: Text(skill.name), value: skill.name)));
        }
      }
//^this code populates each ListTile (one for each combatant) with a drop down button of all their combat skills
      return ListTile(

        leading: comba.port,
        title: Text(comba.info),
        onTap: () {
          if(comba.faction == "good"){
            _fighterFightInfo(comba.guy, theQuest.boss); //separate page with more detailed info, not finished
          }
          else{
            _monsterFightInfo(theQuest.boss); //same but for monsters
          }
        },
        trailing: Row(
          mainAxisSize: MainAxisSize.min,
          children: [

            DropdownButton( //HERE IS WHERE THE ERROR LIES
              value: skillChoice,
              items: listDrop,
              hint: Text("Choose Skill"),
              onChanged: (value) {
                setState(() {
                  skillChoice = value;
                });
              },
            ),
            IconButton(icon: Icon(Icons.check), onPressed: (){
//eventually this button will be used to execute the user's skill choice
            })
          ],
        ),
        subtitle: Text(comba.hp.toString()),
      );
    },
    );
    Navigator.of(context).push(
      MaterialPageRoute<void>(
        builder: (BuildContext context) {
//I have tried moving most of the above code into here, 
//and also implementing StatelessBuilders here and other places in the below code to no effect
          final divided = ListTile.divideTiles(
            context: context,
            tiles: tiles,
          ).toList();
          return Scaffold(
            appBar: AppBar(
              title: Text("Slay "+theQuest.boss.name+"  "+theQuest.boss.level.toString()+"  "+theQuest.boss.type.name, style: TextStyle(fontSize: 14),),
              leading: IconButton(icon: Icon(Icons.arrow_back), onPressed: () {
                _squadSelect(theQuest);
              }),
            ),
            body: ListView(children: divided),
          );
        },
      ),
    );
  }
//there are a lot more methods here which I haven't included
 @override

  Widget build(BuildContext context) {
//I can show this if you need it but there's a lot of UI building on the main page
//Also might not be the most efficiently implemented
//what you need to know is that there are buttons which call _fight and go to that page
}
class Main extends StatefulWidget {
  @override
  MainState createState() => MainState();
}

Спасибо за любую помощь или совет, которые вы можете предложить.

Ответы [ 2 ]

0 голосов
/ 31 мая 2020

В следующем вопросе содержится информация, которая помогла мне найти ответ. Другой вопрос, но решение применимо. Спасибо пользователю: 4576996 Sven. В основном мне нужно переформатировать мои построения в void _fight на новую страницу с отслеживанием состояния. Это может быть полезно для всех, кто использует начальное руководство в качестве основы для создания своего приложения.

flutter удалить элемент из списка

0 голосов
/ 29 мая 2020

Немного сложно понять, что здесь происходит, поэтому, если возможно, добавьте проблемные области в новый виджет и разместите его здесь.

В любом случае, сейчас кажется, что ваша переменная skillShare является локальной, поэтому каждый раз, когда вы устанавливаете состояние, она не обновляется. Попробуйте что-то вроде этого:

class MainState extends State<Main> {
String skillShare = ""; //i.e make skillShare a global variable
final List<Fighter> _squad = List<Fighter>(); 
...