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 {
final List<Shadow>? iconShadows = shadows ?? iconTheme.shadows;
final IconData? icon = this.icon;
if (icon == null) {
return Semantics(
label: semanticLabel,
......@@ -263,30 +264,34 @@ class Icon extends StatelessWidget {
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(
overflow: TextOverflow.visible, // Never clip.
textDirection: textDirection, // Since we already fetched it for the assert...
text: TextSpan(
text: String.fromCharCode(icon!.codePoint),
style: 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,
),
text: String.fromCharCode(icon.codePoint),
style: fontStyle,
),
);
if (icon!.matchTextDirection) {
if (icon.matchTextDirection) {
switch (textDirection) {
case TextDirection.rtl:
iconWidget = Transform(
......
......@@ -128,6 +128,22 @@ void main() {
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 {
await tester.pumpWidget(
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