28

I want to add icon to left of DropDownButton but can't find a way to do so. What I want to achieve is like this:

enter image description here

I have tried following code but it places icon to right where I don't want it and it also overrides arrow icon:

 `@override
  Widget build(BuildContext context) {
  return Scaffold(
  body: Container(
    margin: EdgeInsets.only(top: 64.0, left: 16.0, right: 16.0),
    color: Colors.white,
    child: DropdownButton(
      icon: Icon(
        Icons.person,
        color: Colors.redAccent,
        size: 20.09,
      ),
      isExpanded: true,
      items: _studentList.map((val) {
        return DropdownMenuItem(
          value: val,
          child: Text(val),
        );
      }).toList(),
      value: _currentSelectedItem,
      onChanged: (value) {
        setState(() {
          _currentSelectedItem = value;
        });
      },
    ),
  ),
);
  }`

Output of above code is like this:

enter image description here

I have also tried to place Icon() and DropDownButton() inside Row() widget but that does not allow the DropDownButton() to expand to full width.

Any help would be appreciated.

Thanks

Muhammad Faizan
  • 1,891
  • 2
  • 18
  • 37

8 Answers8

27

Use DropdownButtonFormField as it has decoration property. You can use prefixIcon attribute to set icon on left side.

Example:

DropdownButtonFormField<String>(
         decoration: InputDecoration(
         prefixIcon: Icon(Icons.person),
         ),
         hint: Text('Please choose account type'),
         items: <String>['A', 'B', 'C', 'D'].map((String value) {
         return DropdownMenuItem<String>(
         value: value,
         child: new Text(value),
       );
      }).toList(),
     onChanged: (_) {},
),

Result:

enter image description here

Zeeshan Ali
  • 667
  • 8
  • 16
16

There is no specific attribute for adding icon the way you want but you can always work around your code and find some tweaks. Use the following code which will place you Icon() on top of your DropDownButton() button.

@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
  children: <Widget>[
    Container(
      decoration: BoxDecoration(
        color: Colors.white,
        boxShadow: [
          BoxShadow(
            color: Colors.grey,
            blurRadius: 20.0,
            spreadRadius: 0.5,
            offset: Offset(1.0, 1.0),
          ),
        ],
      ),
      padding: EdgeInsets.only(left: 44.0),
      margin: EdgeInsets.only(top: 64.0, left: 16.0, right: 16.0),
      child: DropdownButton(
        isExpanded: true,
        items: your_list.map(
          (val) {
            return DropdownMenuItem(
              value: val,
              child: Text(val),
            );
          },
        ).toList(),
        value: _currentSelectedItem,
        onChanged: (value) {
          setState(() {
            _currentSelectedItem = value;
          });
        },
      ),
    ),
    Container(
      margin: EdgeInsets.only(top: 80.0, left: 28.0),
      child: Icon(
        Icons.person,
        color: Colors.redAccent,
        size: 20.0,
      ),
    ),
  ],
),
  );
}
Sameed Shah
  • 254
  • 1
  • 6
3

Remember, everything is a widget, so:

iconSize: 0,
hint: Row(
         children: [
            Container(
                child: Text('Freguesias'),
            ),
            Container(
                child: Icon(Icons.arrow_drop_down),
            ),
          ],
 ),
1

This may too late. But will helpful for upcoming viewers.

Instead of using DropDownButton, we can use DropDownButtonFormField. Which has a decoration property. With this we can make use of prefixIcon property to add icon to the left side of DropDownButton:

DropDownButtonFormField(
  decoration: InputDecoration(
    prefixIcon: Icon(Icons.person, color: Colors.redAccent),
  ),
  ...
);
Vinoth B
  • 11
  • 2
0

If the icon really should be visually part of the DropDown component, you could go the following route. Its a bit hacky and lacks being responsive but its a start for some more experiments. I added a complete working example so you can copy paste it to a runnable main dart file.

In a nutshell, it uses a Stack layout so the icon is just placed over the dropdown component. Then i padded the Text so that there is space to the left.

void main() => runApp(MyApp());

/// This Widget is the main application widget.
class MyApp extends StatelessWidget {
  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: _title,
      home: Scaffold(
        appBar: AppBar(title: const Text(_title)),
        body: MyStatefulWidget(),
      ),
    );
  }
}

class MyStatefulWidget extends StatefulWidget {
  MyStatefulWidget({Key key}) : super(key: key);

  @override
  _MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  String dropdownValue = 'One';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Stack(
          children: <Widget>[
            DropdownButton<String>(
              value: dropdownValue,
              //icon: Icon(Icons.arrow_downward),
              iconSize: 24,
              elevation: 16,
              style: TextStyle(color: Colors.deepPurple),
              underline: Container(
                height: 2,
                color: Colors.deepPurpleAccent,
              ),
              onChanged: (String newValue) {
                setState(() {
                  dropdownValue = newValue;
                });
              },
              items: <String>['One', 'Two', 'Free', 'Four']
                  .map<DropdownMenuItem<String>>((String value) {
                return DropdownMenuItem<String>(
                  value: value,
                  child: Padding(
                    padding: const EdgeInsets.only(left: 30.0),
                    child: Text("$value"),
                  ),
                );
              }).toList(),
            ),
            Container(
                margin: EdgeInsets.symmetric(vertical: 10),
                child: Icon(Icons.arrow_downward)),
          ],
        ),
      ),
    );
  }
}
Logemann
  • 2,767
  • 33
  • 53
0

try to use decoration property of DropdownButtonFormField and use prefixIcon property.

DropdownButtonFormField(
      isDense: false,
      itemHeight: 48,
      isExpanded: true,
      decoration: InputDecoration(
        prefixIcon: Icon(Icons.question_answer_rounded),//Add this line
        filled: true,
        ...
        ),
        ...
  )
        

This will add an icon at left.

-2

Wrapping your icon and dropdown widget inside a row widget, nested inside a container will do the work like below:

body: Container(
    margin: EdgeInsets.only(top: 64.0, left: 16.0, right: 16.0),
    color: Colors.white,
    child: 
    child: Row(
    children: <Widget>[
      Icon(
        Icons.person,
        color: Colors.redAccent,
        size: 20.09,
     ),
     Expanded(
        flex:1,
        child:DropdownButton(
            isExpanded: true,
            items: _studentList.map((val) {
            return DropdownMenuItem(
              value: val,
              child: Text(val),
            );
        }).toList(),
        value: _currentSelectedItem,
        onChanged: (value) {
         setState(() {
           _currentSelectedItem = value;
         });
      },
     ),
    )
  ]  
)
Muhammad Faizan
  • 1,891
  • 2
  • 18
  • 37
Dhaval Patel
  • 369
  • 1
  • 8
-2

Simple way to do this would be to pass child prop to DropdownMenuItem, you can then pass any widget, i have created a row and passed the icon and text in the row :

items: <String>['George Green School', 'George Blue School', 'George Red School', 'George Yellow School']
                .map<DropdownMenuItem<String>>((String value) {
              return DropdownMenuItem<String>(
                value: value,
                child: Row(
                  children: [
                    Icon(Icons.dangerous),
                    Text(value, style: TextStyle(fontSize : 12),),
                  ],
                ),
              );
            }).toList(),