Unverified Commit f2b74725 authored by LongCatIsLooong's avatar LongCatIsLooong Committed by GitHub

Ensure Icon vertically centers its icon glyph. (#138937)

Fixes https://github.com/flutter/flutter/issues/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.
parent 223f32e0
...@@ -250,6 +250,7 @@ class Icon extends StatelessWidget { ...@@ -250,6 +250,7 @@ class Icon extends StatelessWidget {
final List<Shadow>? iconShadows = shadows ?? iconTheme.shadows; final List<Shadow>? iconShadows = shadows ?? iconTheme.shadows;
final IconData? icon = this.icon;
if (icon == null) { if (icon == null) {
return Semantics( return Semantics(
label: semanticLabel, label: semanticLabel,
...@@ -263,30 +264,34 @@ class Icon extends StatelessWidget { ...@@ -263,30 +264,34 @@ class Icon extends StatelessWidget {
iconColor = iconColor.withOpacity(iconColor.opacity * iconOpacity); iconColor = iconColor.withOpacity(iconColor.opacity * iconOpacity);
} }
final TextStyle fontStyle = TextStyle(
fontVariations: <FontVariation>[
if (iconFill != null) FontVariation('FILL', iconFill),
if (iconWeight != null) FontVariation('wght', iconWeight),
if (iconGrade != null) FontVariation('GRAD', iconGrade),
if (iconOpticalSize != null) FontVariation('opsz', iconOpticalSize),
],
inherit: false,
color: iconColor,
fontSize: iconSize,
fontFamily: icon.fontFamily,
package: icon.fontPackage,
fontFamilyFallback: icon.fontFamilyFallback,
shadows: iconShadows,
height: 1.0, // Makes sure the font's body is vertically centered within the iconSize x iconSize square.
leadingDistribution: TextLeadingDistribution.even,
);
Widget iconWidget = RichText( Widget iconWidget = RichText(
overflow: TextOverflow.visible, // Never clip. overflow: TextOverflow.visible, // Never clip.
textDirection: textDirection, // Since we already fetched it for the assert... textDirection: textDirection, // Since we already fetched it for the assert...
text: TextSpan( text: TextSpan(
text: String.fromCharCode(icon!.codePoint), text: String.fromCharCode(icon.codePoint),
style: TextStyle( style: fontStyle,
fontVariations: <FontVariation>[
if (iconFill != null) FontVariation('FILL', iconFill),
if (iconWeight != null) FontVariation('wght', iconWeight),
if (iconGrade != null) FontVariation('GRAD', iconGrade),
if (iconOpticalSize != null) FontVariation('opsz', iconOpticalSize),
],
inherit: false,
color: iconColor,
fontSize: iconSize,
fontFamily: icon!.fontFamily,
package: icon!.fontPackage,
fontFamilyFallback: icon!.fontFamilyFallback,
shadows: iconShadows,
),
), ),
); );
if (icon!.matchTextDirection) { if (icon.matchTextDirection) {
switch (textDirection) { switch (textDirection) {
case TextDirection.rtl: case TextDirection.rtl:
iconWidget = Transform( iconWidget = Transform(
......
...@@ -128,6 +128,22 @@ void main() { ...@@ -128,6 +128,22 @@ void main() {
expect(richText.text.style!.fontFamily, equals('Roboto')); expect(richText.text.style!.fontFamily, equals('Roboto'));
}); });
testWidgetsWithLeakTracking("Icon's TextStyle makes sure the font body is vertically center-aligned", (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/138592.
await tester.pumpWidget(
const Directionality(
textDirection: TextDirection.ltr,
child: Center(
child: Icon(IconData(0x41)),
),
),
);
final RichText richText = tester.firstWidget(find.byType(RichText));
expect(richText.text.style?.height, 1.0);
expect(richText.text.style?.leadingDistribution, TextLeadingDistribution.even);
});
testWidgetsWithLeakTracking('Icon with custom fontFamilyFallback', (WidgetTester tester) async { testWidgetsWithLeakTracking('Icon with custom fontFamilyFallback', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const Directionality( const Directionality(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment