Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fix DropdownButtonFormField icon not vertically centered #163205

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

bleroux
Copy link
Contributor

@bleroux bleroux commented Feb 13, 2025

Description

This PR fixes DropdownButtonFormField suffix icon vertical alignment when DropdownButtonFormField.inputDecoration is provided without a hint text.

Before:

The dropdown icon is misaligned vertically:

image

After:

The dropdown icon is aligned vertically:

image

Related Issue

Fixes DropdownButtonFormField arrow icon is misaligned vertically

Tests

Adds 1 test.

@github-actions github-actions bot added framework flutter/packages/flutter repository. See also f: labels. f: material design flutter/packages/flutter/material repository. labels Feb 13, 2025
@bleroux bleroux force-pushed the fix_dropdown_button_form_field_icon_not_vertically_centered branch 3 times, most recently from 3b28af6 to 955fb0b Compare February 13, 2025 13:27
@bleroux bleroux requested a review from justinmc February 13, 2025 18:34
@bleroux
Copy link
Contributor Author

bleroux commented Feb 13, 2025

@justinmc This PR replaces #159328 as the workaround that was used in #159328 is no more needed since #159975 was merged.

Copy link
Contributor

@justinmc justinmc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's really good that #159975 simplified the solution here.

LGTM but let's see if the Google tests pass.

@bleroux bleroux force-pushed the fix_dropdown_button_form_field_icon_not_vertically_centered branch from 955fb0b to 4d79b7a Compare February 27, 2025 08:09
InputDecoration effectiveDecoration = widget._inputDecoration!.copyWith(
// Override the suffix icon constraints to allow the
// icon alignment to match the regular dropdown button.
suffixIconConstraints: const BoxConstraints(minWidth: 40.0),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like there are some Google failures where some text that used to fit inside of the dropdown no longer fits, as if the horizontal space available in the field has been reduced. Is that due to this minWidth constraints change? Is that horizontal space change intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, interesting!

as if the horizontal space available in the field has been reduced

I don't remember why we choose to set the minWidth to 40.0. Maybe something from a previous version of the PR.
I updated the PR to set minWidth to 24.0. But it won't be enough to get the same available horizontal space for the input compared to before this PR.

The reason is that for InputDecoration there is 4.0 default gap between the input and the suffixIcon.
Previous version of the DropdownButtonFormField did not rely on InputDecoration.suffixIcon so it was not impacted by this gap.

I added an experimental commit to this PR to make it possible to remove this gap. This will not be the final solution, it is only a temporary commit to see if it helps with the Google testing failures.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@justinmc Are there many Google testing failures now?
The PR is in an experimental state (see my previous comment). The number and the kind of Google testing failures will determine how to proceed there. Thanks for having a look when you will get bandwidth (no hurry there).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any failures of the sort that I mentioned, where text no longer fits. In fact, I see some case where more text now fits than did before. However, the suffix is very close to the right edge now.

Sorry I missed this notification, feel free to ping me if I disappear again :)

@bleroux bleroux force-pushed the fix_dropdown_button_form_field_icon_not_vertically_centered branch 3 times, most recently from adaa282 to 5e67747 Compare March 24, 2025 15:06
@bleroux bleroux requested a review from justinmc April 7, 2025 07:22
@bleroux
Copy link
Contributor Author

bleroux commented Apr 18, 2025

Many thanks for the feedback 🙏 .
Based on #163205 (comment). I will mark this PR as draft, file a separate PR to make the inputDecoration prefix and suffix gaps configurable. And then come back to this PR. Especially trying to understand in which cases "the suffix is very close to the right edge now".

@bleroux bleroux marked this pull request as draft April 18, 2025 08:41
@flutter-dashboard
Copy link

This pull request has been changed to a draft. The currently pending flutter-gold status will not be able to resolve until a new commit is pushed or the change is marked ready for review again.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

@justinmc
Copy link
Contributor

Here's what I meant by the suffix icon being close to the right side:

The master branch Your screenshot of this PR in the description This PR currently
Screenshot 2025-04-18 at 11 23 33 AM 412859218-b5704453-66a3-4cb2-97ff-bef556bff377 Screenshot 2025-04-18 at 11 22 13 AM

You can see in the PR currently the suffix icon is further to the right than it was before you changed the PR.

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Center(
              child: SizedBox(
                width: 200,
                child: DropdownButtonFormField<String>(
                  onChanged: (_) {},
                  decoration: InputDecoration(
                    fillColor: Colors.blueGrey.withOpacity(0.2),
                    filled: true,
                    labelText: 'Label text',
                  ),
                  items: [
                    DropdownMenuItem(
                      value: 'selected',
                      child: Text('Selected item'),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

@bleroux
Copy link
Contributor Author

bleroux commented Apr 18, 2025

Wow, thanks a lot for providing this sample and the screenshot.
For the moment, I'm surprised that the screenshot in my PR description did not match the result you got. I will try to find why there is such a discrepancy (maybe related to another InputDecoration parameter or maybe related to the platform used to run the sample). Anyway, thanks a lot for providing these very useful feedback 🙏

@bleroux bleroux force-pushed the fix_dropdown_button_form_field_icon_not_vertically_centered branch 2 times, most recently from 2126ae4 to 746ae5b Compare April 25, 2025 13:43
@bleroux
Copy link
Contributor Author

bleroux commented Apr 25, 2025

@justinmc I updated the PR based on your last comment and our discussion on #167558 (comment)

It turned out that the fix, in order to compute the correct suffixIconConstraints, should take into account if the input decoration is filled or outlined.

Because for a filled or outlined decoration the right padding is directly provided by the constraints added to the suffix icon, for instance constraints on mobile are 48x48 which means a left and right padding of 12.0. (FYI, on desktop it is be 8.0 because the suffixIconConstraints is 40x40, this is probably not intended as from the M3 spec, visual density usually applies only on the vertical direction, I will check that and file an issue if needed).

I updated the fix accordingly. Let me know how it goes with the Google tests.
FYI, I will need to add some more tests for verifying this fix.

And let me try to explain the layout:

Before the fix

DropdownButtonFormField was positioning the icon by setting the input decoration content to a Row containing both the selected item label and the icon (24x24).

For a filled or outlined decoration, the horizontal layout was: leftPadding (16.0) | selected item label | icon (24.0) | rightPadding (16.0).
(16.0 padding since very recently because it is due to #162157, before it was 12.0).

For a non-filled and non-outlined decoration, it was: leftPadding (0.0) | selected item label | icon (24.0) | rightPadding (0.0)

With the fix

DropdownButtonFormField is positioning the icon by setting the input decoration suffixIcon and suffixIconConstraints.

For a filled or outlined decoration, the horizontal layout is: leftPadding (16.0) | selected item label | suffixIconGap (4.0) | icon (24.0) | rightPadding (12.0).
Here the right padding is 12.0 and this is the compliant padding from the M3 spec: when there is no suffix icon right padding should be 16.0, when the is a suffixIcon it should be 12.0).
This means that, with the fix, the content's width is the same as before this fix. The difference is the icon moving by 4.0 pixel to the right (which will restore its position as before #162157).

For a non-filled and non-outlined decoration, it is: leftPadding (0.0) | selected item label | icon (24.0) | suffixIconGap (4.0) | rightPadding (0.0)
Here the difference will be the content width being reduced by 4.0 pixel and the icon should be at the same horizontal position.

Here is a combined screenshot to illustrate this. The top 3 fields showcase the fix, the bottom ones were captured without the fix:

image

Code sample for the screenshot
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  final bool filled = true;
  static const List<DropdownMenuItem<String>> items = [
    DropdownMenuItem(value: 'selected', child: Text('Selected item')),
  ];

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: SizedBox(
            width: 200,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              spacing: 4.0,
              children: [
                DropdownButtonFormField<String>(
                  onChanged: (_) {},
                  decoration: const InputDecoration(labelText: 'Raw'),
                  // Before https://github.com/flutter/flutter/pull/163205, width could be 176.
                  selectedItemBuilder:
                      (context) => [Container(height: 24, width: 172, color: Colors.amber)],
                  items: items,
                ),
                DropdownButtonFormField<String>(
                  onChanged: (_) {},
                  decoration: const InputDecoration(labelText: 'Filled', filled: true),
                  selectedItemBuilder:
                      (context) => [Container(height: 24, width: 144, color: Colors.amber)],
                  items: items,
                ),
                DropdownButtonFormField<String>(
                  onChanged: (_) {},
                  decoration: const InputDecoration(
                    labelText: 'Outlined',
                    border: OutlineInputBorder(),
                  ),
                  selectedItemBuilder:
                      (context) => [Container(height: 24, width: 144, color: Colors.amber)],
                  items: items,
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

@bleroux bleroux force-pushed the fix_dropdown_button_form_field_icon_not_vertically_centered branch from 746ae5b to fa581cf Compare May 5, 2025 14:53
@bleroux bleroux marked this pull request as ready for review May 5, 2025 19:42
@bleroux bleroux force-pushed the fix_dropdown_button_form_field_icon_not_vertically_centered branch from fa581cf to 44fcdf4 Compare May 5, 2025 19:42
@bleroux bleroux force-pushed the fix_dropdown_button_form_field_icon_not_vertically_centered branch from 44fcdf4 to 25ff01a Compare May 6, 2025 18:40
@justinmc
Copy link
Contributor

justinmc commented May 6, 2025

Nice, I ran it locally and confirmed that the layout seems to be correct as you explained. The Google test check has disappeared though, let me try re-adding it.

Edit: Possibly an infrastructure problem (Google internal b/416058821) so I'm running the Google tests manually.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

DropdownButtonFormField arrow icon is misaligned vertically
2 participants