Search code examples
flutterdartdrop-down-menu

Adjust the size of the DropdownMenuItem in Flutter


I have created a textfield, which has a dropdown button with the history of the textfield. What concerns me is that this field will be used to display IP address, which does not fit as I want in the history dropdown:

IP does not fit

as you can see, the address is on two lines instead of one, which is as big as the textfield for example (200px in this case). I tried wrapping the DropdownMenuItem in a SizedBox and fixing its width to 200px for example but did not work.. Here is my Widget:

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

class HistoryTextField extends StatefulWidget {
  final String fieldType;
  final String hintText;

  const HistoryTextField(
      {super.key, required this.fieldType, required this.hintText});

  @override
  State<HistoryTextField> createState() => _HistoryTextFieldState();
}

class _HistoryTextFieldState extends State<HistoryTextField> {
  final TextEditingController _controller = TextEditingController();
  final List<String> _history = [];
  String? _selectedHistory;

  @override
  void initState() {
    super.initState();
    // Load history from storage
    _loadHistory();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  Future<void> _loadHistory() async {
    // Load history from storage
    final preferences = await SharedPreferences.getInstance();

    setState(() {
      _history.addAll(preferences.getStringList(widget.fieldType) ?? []);

      if (_history.isNotEmpty) {
        _selectedHistory = _history.first;
        _controller.text = _selectedHistory!;
      }
    });
  }

  Future<void> _saveHistory() async {
    // Save history to storage
    final preferences = await SharedPreferences.getInstance();
    preferences.setStringList(widget.fieldType, _history);
  }

  void _addToHistory(String text) {
    if (text.isNotEmpty && !_history.contains(text)) {
      _history.insert(0, text);
      // Save history to storage
      _saveHistory();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        color: Theme.of(context).scaffoldBackgroundColor,
        border: Border.all(color: Theme.of(context).dividerColor),
        borderRadius: BorderRadius.circular(5),
      ),
      padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
      child: Row(
        children: [
          Expanded(
            child: TextField(
              cursorColor: Theme.of(context).dividerColor,
              decoration: InputDecoration(
                  border: InputBorder.none, hintText: widget.hintText),
              controller: _controller,
              onChanged: (value) {
                setState(() {
                  _selectedHistory = null;
                });
              },
              onSubmitted: (value) {
                _addToHistory(value);
              },
            ),
          ),
          SizedBox(
            width: 50,
            child: DropdownButtonHideUnderline(
              child: DropdownButton<String>(
                isExpanded: true,
                value: _selectedHistory,
                onChanged: (String? newValue) {
                  setState(() {
                    _selectedHistory = newValue;
                    _controller.text = newValue!;
                  });
                },
                selectedItemBuilder: (BuildContext context) {
                  return _history.map<Widget>((String value) {
                    return Container();
                  }).toList();
                },
                items: _history.map<DropdownMenuItem<String>>((String value) {
                  return DropdownMenuItem<String>(
                    value: value,
                    child: Text(
                      value,
                      textAlign: TextAlign.left,
                    ),
                  );
                }).toList(),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

and here is how I have it used:

class _IpSelection extends StatelessWidget {
  const _IpSelection();

  @override
  Widget build(BuildContext context) {
    return const Row(
      children: [
        Text("IP Адрес: ", style: TextStyle(fontWeight: FontWeight.bold)),

        SizedBox(width: 20),

        // IP Address text field
        SizedBox(
            width: 200,
            child: HistoryTextField(
              fieldType: "ipField",
              hintText: "Въведете IP адрес",
            ))
      ],
    );
  }
}

Solution

  • The reason why your content fit 2 strings inside dropdown, is that you explicitly wrap your DropdownButtonHideUnderline inside SizedBox with width: 50 (in your first code sample). That width controls your DropdownButton's width.

    Also There is a menuWidth inside DropdownButton widget. Its documentation says:

    If it is not provided, the width of the menu is the width of the button.

    So you can provide menuWidth with desired size, or provide double.infinite to make it fill all available space.