Can't figure out how to properly style DropdownButton

Viewed 227

I'm kinda new to Flutter and I'm building an app for a college project, but I'm having problems with this widget.

DropdownButton input value in white color

DropdownButton input value in black color

This is my DropdownButton code, it appears with the Hint in white color, but when I select an item the value in the button appears as black. If I change the DropdownButton color to white, then when the popup appears the background-color is white and so the font-color. This way I can't see the items, because they're the same color as the background.

class DropdownWidget extends StatelessWidget {
  final IconData icon;
  final IconData arrowIcon;
  final String hint;
  final List items;
  final Stream stream;
  final Function onChanged;

  DropdownWidget({this.icon, this.arrowIcon, this.hint, this.items, this.stream, this.onChanged});

  @override
  Widget build(BuildContext context) {
    return StreamBuilder(
      stream: stream,
      builder: (context, snapshot) {
        print("Snapshot data -> ${snapshot.data}");
        return InputDecorator(
          child: DropdownButton(
            icon: Icon( arrowIcon, color: Colors.white,),
            hint: Text( hint, style: TextStyle(color: Colors.white),),
            items: items.map((value) {
              print("Valor do item $value");
              return DropdownMenuItem(
                value: value,
                child: Text(value.runtimeType == int ? value.toString() : value, style: TextStyle(color: Colors.black),),
              );
            }).toList(),
            onChanged: onChanged,
            value: snapshot.data,
            isExpanded: true,
            style: TextStyle(
//              color: Colors.black,
              color: Theme.of(context).textSelectionColor,
              fontSize: 18.0,
            ),
            underline: Container(),
            isDense: true,
          ),
          decoration: InputDecoration(
            icon: icon == null ? null : Icon(icon, color: Colors.white,),
            hintText: hint,
            hintStyle: TextStyle(color: Colors.white),
            focusedBorder: UnderlineInputBorder(
              borderSide: BorderSide(color: Theme.of(context).primaryColor)
            ),
            contentPadding: EdgeInsets.only(
              left: 5,
              right: 0,
              bottom: 24,
              top: 30
            ),
            errorText: snapshot.hasError ? snapshot.error : null,
          ),
        );
      }
    );
  }
}

What could I do to solve this? Is there a way to make the popup's background-color darker or just the value inside the button in a different color from the item's color?

2 Answers

You have to wrap your DropDownButton in a Theme. Example code:

Theme(
    data: ThemeData(canvasColor: Colors.black), //this is where the magic happens
    child: DropdownButton<String>(
      value: dropDownValue,
      onChanged: (String newValue) {
        setState(() {
          dropDownValue = newValue;
        });
      },

For those, who have also smashed against the brutal reality finding a way to add a dropdown with Flutter.

As mentioned by @asterisk12 adding canvasColor to the Theme is the way to change the background for the dropdown list.

My answer is for the rest of you still battling with OTHER styling issues I am leaving here an example of how I managed to achieve (almost) what I needed:

  • list appears below the button
  • button is rectangular
  • there is a hint text
  • list is the same width as button

enter image description here enter image description here

For it to work you will need a dropdown_button2 dependency (https://pub.dev/packages/dropdown_button2/install)

class DropDownButton extends StatefulWidget {
  final List<String> options;

  const DropDownButton({Key? key, required this.options}) : super(key: key);

  @override
  State<DropDownButton> createState() => _DropDownButtonState();
}

class _DropDownButtonState extends State<DropDownButton> {
  String? selectedValue;

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: 70,
      child: Container(
        margin: const EdgeInsets.fromLTRB(2, 5, 2, 5),
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.circular(3),
        ),
        child: DropdownButtonHideUnderline(
          child: DropdownButton2<String>(
              dropdownElevation: 0,
              hint: const Text(
                'Select Item',
              ),
              icon: const Icon(
                Icons.arrow_downward,
              ),
              iconSize: 30,
              isExpanded: true,
              iconEnabledColor: Colors.teal,
              buttonPadding: EdgeInsets.all(12),
              value: selectedValue,
              dropdownMaxHeight: 150,
              scrollbarAlwaysShow: true,

              items: widget.options
                  .map((e) => DropdownMenuItem(value: e, child: Text(e)))
                  .toList(),
              offset: const Offset(0, 3),

              onChanged: (value) {
                setState(() {
                  selectedValue = value;
                });
              }),
        ),
      ),
    );
  }
}

Details:

  • remove the shadow from the list: dropdownElevation: 0

  • add a custom icon to DropdownButton2:

 icon: const Icon(
     Icons.arrow_downward,),
 iconSize: 30,
  • Making the list scrollbar(you see it only when all elements do not fit in the dropdown, you can make dropdownMaxHeight smaller to see the difference).
scrollbarAlwaysShow: true,
  • Last but not least change the position of the list:

you can go wild :D and make some weird position offset: const Offset(-20, -3), enter image description here

or you can go not that wild and keep it as in my example so, that there is no space between button and the list offset: const Offset(0, 3),

enter image description here

Hope I could help someone as desperate as I have recently been and save a bit of time for you.

Related