0

I am trying to create a custom widget for DropDownButton. It seems to work fine. The onChanged() func is also working when I take console print of the changed value. However, I am not able to view the text in the box after the Onchanged() func.

Can someone let me know what could be wrong with the same? My code with the widget is below:

 import 'package:flutter/material.dart';
    import 'package:shared_preferences/shared_preferences.dart';
    
    class InputScreen2 extends StatefulWidget {
      final List<double> sizes;
      const InputScreen2({Key? key, required this.sizes}) : super(key: key);
    
      @override
      State<InputScreen2> createState() => _InputScreen2State();
    }
    
    class _InputScreen2State extends State<InputScreen2> {
      Future? future;
      double screenwd = 0, screenht = 0;
      List<String> listsex = ['Male', 'Female'];
      String? sex;
    
      @override
      void initState() {
        // TODO: implement initState
        future = _future();
        super.initState();
      }
    
      Future<int> _future() async {
        SharedPreferences prefs = await SharedPreferences.getInstance();
        screenwd = widget.sizes[0];
        screenht = widget.sizes[1];
    
        return 0;
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            backgroundColor: Colors.orange,
            body: FutureBuilder(
                future: future,
                builder: (context, snapshot) {
                  if (snapshot.hasError) {
                    return Center(
                        child: Text(
                      'Data Error...Please try again',
                      style: Theme.of(context).textTheme.titleSmall,
                    ));
                  } else if (snapshot.connectionState == ConnectionState.waiting) {
                    return Text(
                      'Waiting',
                      style: Theme.of(context).textTheme.titleSmall,
                    );
                  } else if (!snapshot.hasData) {
                    return Text(
                      'No Data',
                      style: Theme.of(context).textTheme.titleSmall,
                    );
                  } else if (snapshot.hasData) {
                    //Block I====================================================
                    return SafeArea(
                      child: Center(
                        child: Container(
                          padding: const EdgeInsets.all(20.0),
                          decoration: BoxDecoration(
                              border: Border.all(width: 2.0), color: Colors.blue),
                          width: screenwd * .8,
                          height: screenht * .75,
                          child: SingleChildScrollView(
                            child: Column(
                              children: [
                                Row(
                                  mainAxisAlignment: MainAxisAlignment.start,
                                  children: [
                                    const Text(
                                      'Personal Details',
                                    ),
                                    const SizedBox(
                                      width: 23,
                                    ),
                                    dropDownMenu('Sex', sex, listsex),
                                  ],
                                ),
                              ],
                            ),
                          ),
                        ),
                      ),
                    );
                  }
                  return const Text('No DATA');
                }));
      }
    
      Widget dropDownMenu(String title, String? inputTxt, List<String> stringList) {
        return Container(
          margin: const EdgeInsets.only(top: 10.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                title,
              ),
              Container(
                width: 80,
                height: 35,
                decoration: BoxDecoration(
                    border: Border.all(color: Colors.white, width: 1.0),
                    borderRadius: const BorderRadius.all(Radius.circular(5.0))),
                child: DropdownButton<String>(
                    value: inputTxt,
                    dropdownColor: Colors.amber,
                    items: stringList.map<DropdownMenuItem<String>>((String value) {
                      return DropdownMenuItem<String>(
                          value: value,
                          child: Text(
                            value,
                            style: const TextStyle(color: Colors.white),
                          ));
                    }).toList(),
                    onChanged: (String? value) {
                      setState(() {
                        inputTxt = value!;
                      });
                    }),
              ),
            ],
          ),
        );
      }
    }

1 Answer 1

0

I tried your code in a Dartpad: you have to replace the dropDownMenu onChanged with this

 onChanged: (String? value) {
                  setState(() {
                    sex = value!;
                  });
                }),

I think you just misplaced inputTxt with sex. Probably you don't even need inputTxt in dropDownMenu at all: just replace it with the sex field from _InputScreen2State, like this:

Widget dropDownMenu(String title, List<String> stringList) {
    return Container(
      margin: const EdgeInsets.only(top: 10.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(title),
          Container(
            width: 80,
            height: 35,
            decoration: BoxDecoration(
                border: Border.all(color: Colors.white, width: 1.0),
                borderRadius: const BorderRadius.all(Radius.circular(5.0))),
            child: DropdownButton<String>(
                value: sex,
                dropdownColor: Colors.amber,
                items: stringList.map<DropdownMenuItem<String>>((String value) {
                  return DropdownMenuItem<String>(
                      value: value,
                      child: Text(
                        value,
                        style: const TextStyle(color: Colors.white),
                      ));
                }).toList(),
                onChanged: (String? value) {
                  setState(() {
                    sex = value!;
                  });
                }),
          ),
        ],
      ),
    );
  }

I tested it in the same Dartpad, and it works.


EDIT: so you need to have different dropdowns, each with its different value argument: the problem here I think is that the setState you're invoking in the onChanged argument is not the right one, because DropDownButton is itself a stateful widget, so probably you are setting the state on InputScreen2 without updating the state of DropDownButton, so leaving the field empty. The first solution that comes to mind is to write your own stateful widget that return a DropDownButton (just like your method did):

class MyDropDownButton extends StatefulWidget {
  final String title;
  final List<String> stringList;
  const MyDropDownButton(
      {super.key,
      required this.title,
      required this.stringList});

  @override
  State<MyDropDownButton> createState() => _MyDropDownButtonState();
  
}

class _MyDropDownButtonState extends State<MyDropDownButton> {
  dynamic selectedValue;

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.only(top: 10.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(widget.title),
          Container(
            width: 80,
            height: 35,
            decoration: BoxDecoration(
                border: Border.all(color: Colors.white, width: 1.0),
                borderRadius: const BorderRadius.all(Radius.circular(5.0))),
            child: DropdownButton<String>(
                value: selectedValue,
                dropdownColor: Colors.amber,
                items: widget.stringList
                    .map<DropdownMenuItem<String>>((String value) {
                  return DropdownMenuItem<String>(
                      value: value,
                      child: Text(
                        value,
                        //style: const TextStyle(color: Colors.white),
                      ));
                }).toList(),
                onChanged: (String? value) {
                  setState(() {
                    selectedValue = value!;
                  });
                }),
          ),
        ],
      ),
    );
  }
}

You still need to implement a method in the widget that gets the value from the state (if available) in order to have the value in InputScreen2

Sign up to request clarification or add additional context in comments.

3 Comments

The idea is to have multiple DropdownButtons in one screen. For ex: I have Sex, Month, Year etc as Dropdowns. Hence hardcoding sex is not right. I need to get the selected option into a variable so that I can later write it into database.
ok, i'm gonna edit the answer then.
Sorry for the delayed response. Will try this and confirm. Thanks for the time taken.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.