-1

I am new to flutter, and am trying to code mobile game. So far I have been able to manage through previous questions on forums, youtube tutorials and example apps. However I have hit a wall that I cannot solve.

Many of the features in my UI are supposed to change based on user behavior but do not update, I am using this DropdownButton as my example but it is a problem I am having elsewhere in the code as well. When the user makes a selection from the DropdownButton it should update the value of the button, but instead only the hint is displayed. I have been able to determine through print statements that the selection is registered.

Based on what I have learned so far I suspect that the issue entails my widget's statefulness or lack thereof. I found a few similar questions which suggested using a StatefulBuilder, however when I tried to implement it the code had errors or else duplicated my entire ListTile group. I also saw suggestions about creating a stateful widget instead but the instructions were too vague for me to follow and implement without errors. I am including snippets of the code below, I am hesitant to paste the whole thing because the app is nearly 2000 lines at this point. Please let me know if any further information or code is needed. this is the problematic code, see below for the code in context.

        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();
}

Thank you for any help or advice you can offer.

marc_s
  • 704,970
  • 168
  • 1,303
  • 1,425
  • The code is a bit difficult to understand, so I would suggest you extract the bits of code that are causing the problem and show them in a new widget to make it easier to read. – Mohammad Assad Arshad May 29 '20 at 02:51
  • Does this answer your question? [flutter delete item from listview](https://stackoverflow.com/questions/55142992/flutter-delete-item-from-listview) – desertnaut May 30 '20 at 00:56

2 Answers2

0

Its a bit difficult to understand what is going on here, so if possible add the problem areas in a new widget and post it here.

In any case, for now it seems your skillShare variable is local, so every time you are setting state it does not update. Try something like this:

class MainState extends State<Main> {
String skillShare = ""; //i.e make skillShare a global variable
final List<Fighter> _squad = List<Fighter>(); 
  • I don't have a skillShare variable, do you mean skillChoice? right now it is defined within the ```final tiles = _combatants.map((Combatant comba){``` loop. each ListTile has its own list of skills populated by the combatant it refers to. ```for (Skill skill in comba.guy.skills){ listDrop.add((DropdownMenuItem(child: Text(skill.name), value: comba.guy.skills.indexOf(skill)))); }``` – Ryan Bowman May 29 '20 at 15:35
0

The following question had information which helped me find the answer. Different question but the solution applies. Thanks user:4576996 Sven. Basically I need to reformat from doing my constructing in the void _fight to a new stateful page. This may be useful for anyone else who is using the beginning tutorial as a framework to build their app.

flutter delete item from listview