Home > Back-end >  Flutter DropdownButtonFormField icon doesn't align properly
Flutter DropdownButtonFormField icon doesn't align properly

Time:10-12

Good morning, I am trying to align the DropDown's arrow icon with the hint text but I can't understand why the render engine positions it so far below.

I tried to set the InputDecoration's contentPadding property to EdgeInsets.zero and it seemed to work. However, it ruined the DropDown's focusBorder. Furthermore, I didn't understand what element the padding is attached to.

enter image description here

class WorkpieceFilterBox extends StatefulWidget {
  const WorkpieceFilterBox({
    Key? key,
  }) : super(key: key);

  @override
  State<WorkpieceFilterBox> createState() => _WorkpieceFilterBoxState();
}

class _WorkpieceFilterBoxState extends State<WorkpieceFilterBox> {
  final FocusNode _statusFieldFocus = FocusNode();
  final FocusNode _searchFieldFocus = FocusNode();
  bool hasTextFieldSelected = false;

  void _onFocusChange() {
    setState(() {
      hasTextFieldSelected =
          _statusFieldFocus.hasFocus || _searchFieldFocus.hasFocus;
    });
  }

  @override
  void initState() {
    super.initState();
    _statusFieldFocus.addListener(_onFocusChange);
    _searchFieldFocus.addListener(_onFocusChange);
  }

  @override
  void dispose() {
    super.dispose();
    _statusFieldFocus.removeListener(_onFocusChange);
    _statusFieldFocus.dispose();
    _searchFieldFocus.removeListener(_onFocusChange);
    _searchFieldFocus.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: 55.0,
      child: Stack(
        children: <Widget>[
          _buildGroundLayer(),
          _buildDividerLayer(),
          _buildInputLayer(),
        ],
      ),
    );
  }

  Widget _buildGroundLayer() {
    return Container(
      decoration: BoxDecoration(
        color: Colors.transparent,
        border: Border.all(
          color: Color(0xFFD2D2D2),
          width: 2.5,
        ),
        borderRadius: BorderRadius.circular(27.0),
      ),
    );
  }

  Widget _buildDividerLayer() {
    return SizedBox(
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          Expanded(
            flex: 2,
            child: SizedBox(),
          ),
          Visibility(
            visible: !hasTextFieldSelected,
            child: VerticalDivider(
              width: 8.0,
              thickness: 2.0,
              indent: 10.0,
              endIndent: 10.0,
              color: Color(0xFFD2D2D2),
            ),
          ),
          Expanded(
            flex: 3,
            child: SizedBox(),
          ),
        ],
      ),
    );
  }

  Widget _buildInputLayer() {
    return Row(
      children: <Widget>[
        Expanded(
          flex: 2,
          child: _buildStatusField(),
        ),
        Expanded(
          flex: 3,
          child: _buildSearchField(),
        ),
      ],
    );
  }

  Widget _buildStatusField() {
    return DropdownButtonFormField<String>(
      focusNode: _statusFieldFocus,
      icon: Icon(
        Icons.expand_more,
        size: 30.0,
        color: Color(0xFF2E2E2E),
      ),
      hint: Text(
        'Status',
        style: TextStyle(
          fontSize: 18.0,
          fontWeight: FontWeight.w500,
          color: Color(0xFFA6A6A6),
        ),
      ),
      decoration: InputDecoration(
        enabledBorder: OutlineInputBorder(
          borderSide: BorderSide(
            color: Colors.transparent,
            width: 2.5,
          ),
          borderRadius: BorderRadius.only(
            topLeft: Radius.circular(27.0),
            bottomLeft: Radius.circular(27.0),
          ),
        ),
        focusedBorder: OutlineInputBorder(
          borderSide: BorderSide(
            color: Color(0xFFFF7321),
            width: 2.5,
          ),
          borderRadius: BorderRadius.only(
            topLeft: Radius.circular(27.0),
            bottomLeft: Radius.circular(27.0),
          ),
        ),
      ),
      items: widget.values
          .map<DropdownMenuItem<String>>(
            (WorkpieceStatus status) => DropdownMenuItem<String>(
              value: status.text,
              child: Text(
                status.text,
                style: TextStyle(
                  fontSize: 18.0,
                  fontWeight: FontWeight.w500,
                  color: status.color,
                  fontFamily: 'RobotoFlex-Regular',
                ),
              ),
            ),
          )
          .toList(),
      onChanged: (String? value) => print(value),
    );
  }

  Widget _buildSearchField() {
    return TextField(
      focusNode: _searchFieldFocus,
      cursorColor: Color(0xFF131415),
      decoration: InputDecoration(
        enabledBorder: OutlineInputBorder(
          borderSide: BorderSide(
            color: Colors.transparent,
            width: 2.5,
          ),
          borderRadius: BorderRadius.only(
            topRight: Radius.circular(27.0),
            bottomRight: Radius.circular(27.0),
          ),
        ),
        focusedBorder: OutlineInputBorder(
          borderSide: BorderSide(
            color: Color(0xFFFF7321),
            width: 2.5,
          ),
          borderRadius: BorderRadius.only(
            topRight: Radius.circular(27.0),
            bottomRight: Radius.circular(27.0),
          ),
        ),
        prefixIcon: Icon(
          Icons.search,
          size: 24.0,
          color: Color(0xFF2E2E2E),
        ),
        hintText: 'Search by UII',
        hintStyle: TextStyle(
          fontSize: 18.0,
          fontWeight: FontWeight.w500,
          color: Color(0xFFA6A6A6),
        ),
      ),
      onChanged: (String value) => print(value),
    );
  }
}

CodePudding user response:

DropdownButton is a material component as seen on Broken Dropdown Menu

Here, you can see why setting the height is a bad idea on a Material Component.

Enough talking, what is the solution: Remove the height from SizedBox and any styling that is given by the material component:

return DropdownButtonFormField<String>(
      icon: const Icon(
        Icons.expand_more,
        //size: 30.0,
        color: Color(0xFF2E2E2E),
      ),
      hint: const Text(
        'Status',
        style: TextStyle(
          //fontSize: 18.0,
          //fontWeight: FontWeight.w500,
          color: Color(0xFFA6A6A6),
        ),
      ),

Now I know this will break your UI, but this is how Flutter works. Either you completely adopt the Material Design, or you will have a really bad time.

CodePudding user response:

Try this example code I wrote for you.

My code:

        DropdownButtonHideUnderline(
          child: DropdownButtonFormField<String>(
            decoration: const InputDecoration(
              border: OutlineInputBorder(),
            ),
            icon: const Icon(
              Icons.expand_circle_down, // Custom icon goes here.
            ),
            iconSize: 30, // Icon height goes here.
            hint: const Text('Choose item'),
            value: _dropDownValue,
            items: _dropDownList
                .map(
                  (label) => DropdownMenuItem(
                value: label,
                child: Text(
                  label.toString(),
                ),
              ),
            )
                .toList(),
            onChanged: (value) {
              _dropDownValue = (value ?? _dropDownList[0]);
              setState(() {});
            },
          ),
        ),
  • Related