Skip to content

Commit f2b7472

Browse files
Ensure Icon vertically centers its icon glyph. (#138937)
Fixes flutter/flutter#138592. In an `Icon` widget if the icon font's body (ascender + descender) is larger than the font's units per em, the icon height reported by the text layout library will be larger than the specified font size. When that happens the icon glyph gets pushed towards the bottom because the `Icon` widget is wrapped in a fontSize x fontSize SizedBox and thus has a fixed height of fontSize px. This wasn't a problem for material icons because its UPEM == body.
1 parent 223f32e commit f2b7472

File tree

2 files changed

+38
-17
lines changed

2 files changed

+38
-17
lines changed

packages/flutter/lib/src/widgets/icon.dart

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ class Icon extends StatelessWidget {
250250

251251
final List<Shadow>? iconShadows = shadows ?? iconTheme.shadows;
252252

253+
final IconData? icon = this.icon;
253254
if (icon == null) {
254255
return Semantics(
255256
label: semanticLabel,
@@ -263,30 +264,34 @@ class Icon extends StatelessWidget {
263264
iconColor = iconColor.withOpacity(iconColor.opacity * iconOpacity);
264265
}
265266

267+
final TextStyle fontStyle = TextStyle(
268+
fontVariations: <FontVariation>[
269+
if (iconFill != null) FontVariation('FILL', iconFill),
270+
if (iconWeight != null) FontVariation('wght', iconWeight),
271+
if (iconGrade != null) FontVariation('GRAD', iconGrade),
272+
if (iconOpticalSize != null) FontVariation('opsz', iconOpticalSize),
273+
],
274+
inherit: false,
275+
color: iconColor,
276+
fontSize: iconSize,
277+
fontFamily: icon.fontFamily,
278+
package: icon.fontPackage,
279+
fontFamilyFallback: icon.fontFamilyFallback,
280+
shadows: iconShadows,
281+
height: 1.0, // Makes sure the font's body is vertically centered within the iconSize x iconSize square.
282+
leadingDistribution: TextLeadingDistribution.even,
283+
);
284+
266285
Widget iconWidget = RichText(
267286
overflow: TextOverflow.visible, // Never clip.
268287
textDirection: textDirection, // Since we already fetched it for the assert...
269288
text: TextSpan(
270-
text: String.fromCharCode(icon!.codePoint),
271-
style: TextStyle(
272-
fontVariations: <FontVariation>[
273-
if (iconFill != null) FontVariation('FILL', iconFill),
274-
if (iconWeight != null) FontVariation('wght', iconWeight),
275-
if (iconGrade != null) FontVariation('GRAD', iconGrade),
276-
if (iconOpticalSize != null) FontVariation('opsz', iconOpticalSize),
277-
],
278-
inherit: false,
279-
color: iconColor,
280-
fontSize: iconSize,
281-
fontFamily: icon!.fontFamily,
282-
package: icon!.fontPackage,
283-
fontFamilyFallback: icon!.fontFamilyFallback,
284-
shadows: iconShadows,
285-
),
289+
text: String.fromCharCode(icon.codePoint),
290+
style: fontStyle,
286291
),
287292
);
288293

289-
if (icon!.matchTextDirection) {
294+
if (icon.matchTextDirection) {
290295
switch (textDirection) {
291296
case TextDirection.rtl:
292297
iconWidget = Transform(

packages/flutter/test/widgets/icon_test.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,22 @@ void main() {
128128
expect(richText.text.style!.fontFamily, equals('Roboto'));
129129
});
130130

131+
testWidgetsWithLeakTracking("Icon's TextStyle makes sure the font body is vertically center-aligned", (WidgetTester tester) async {
132+
// Regression test for https://github.com/flutter/flutter/issues/138592.
133+
await tester.pumpWidget(
134+
const Directionality(
135+
textDirection: TextDirection.ltr,
136+
child: Center(
137+
child: Icon(IconData(0x41)),
138+
),
139+
),
140+
);
141+
142+
final RichText richText = tester.firstWidget(find.byType(RichText));
143+
expect(richText.text.style?.height, 1.0);
144+
expect(richText.text.style?.leadingDistribution, TextLeadingDistribution.even);
145+
});
146+
131147
testWidgetsWithLeakTracking('Icon with custom fontFamilyFallback', (WidgetTester tester) async {
132148
await tester.pumpWidget(
133149
const Directionality(

0 commit comments

Comments
 (0)