Flutter:setState((){}无法重绘DropdownButton值

时间:2020-05-29 01:23:50

标签: flutter dart setstate stateful

我是新手,正在尝试编写手机游戏代码。到目前为止,我已经能够解决之前在论坛,youtube教程和示例应用程序中遇到的问题。但是我碰壁了我无法解决的问题。

我的UI中的许多功能都应该根据用户的行为进行更改,但不会更新,我以这个DropdownButton为例,但这也是我在代码的其他地方也遇到的问题。当用户从DropdownButton进行选择时,它应该更新按钮的值,但只会显示提示。我已经能够通过打印语句确定所选内容已注册。

根据我到目前为止所学到的知识,我怀疑问题是由于我的小部件的有状态或缺少状态。我发现了一些类似的问题,建议使用StatefulBuilder,但是,当我尝试实现它时,代码出错或复制了整个ListTile组。我还看到了有关创建有状态窗口小部件的建议,但说明太模糊了,以至于我无法正确执行和执行。我在下面添加了代码片段,因此我很想粘贴整个内容,因为此时应用程序将近2000行。请让我知道是否需要任何进一步的信息或代码。 这是有问题的代码,有关上下文的代码,请参见下文。

        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 :(得分:0)

很难理解这里发生的事情,因此,如果可能的话,将问题区域添加到新的小部件中并将其发布在此处。

无论如何,现在看来您的skillShare变量是本地的,因此,每次设置状态时,它都不会更新。尝试这样的事情:

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

答案 1 :(得分:0)

以下问题提供了有助于我找到答案的信息。不同的问题,但解决方案适用。感谢用户:4576996 Sven。基本上,我需要将在void _fight中的构造重新格式化为新的有状态页面。这对于将入门教程用作构建其应用程序框架的其他人可能很有用。

flutter delete item from listview