diff --git a/dev/tools/gen_defaults/lib/action_chip_template.dart b/dev/tools/gen_defaults/lib/action_chip_template.dart index ade6164e63..32a6a0873a 100644 --- a/dev/tools/gen_defaults/lib/action_chip_template.dart +++ b/dev/tools/gen_defaults/lib/action_chip_template.dart @@ -83,16 +83,24 @@ class _${blockName}DefaultsM3 extends ChipThemeData { @override EdgeInsetsGeometry? get padding => const EdgeInsets.all(8.0); - /// The chip at text scale 1 starts with 8px on each side and as text scaling - /// gets closer to 2 the label padding is linearly interpolated from 8px to 4px. - /// Once the widget has a text scaling of 2 or higher than the label padding - /// remains 4px. + /// The label padding of the chip scales with the font size specified in the + /// [labelStyle], and the system font size settings that scale font sizes + /// globally. + /// + /// The chip at effective font size 14.0 starts with 8px on each side and as + /// the font size scales up to closer to 28.0, the label padding is linearly + /// interpolated from 8px to 4px. Once the label has a font size of 2 or + /// higher, label padding remains 4px. @override - EdgeInsetsGeometry? get labelPadding => EdgeInsets.lerp( - const EdgeInsets.symmetric(horizontal: 8.0), - const EdgeInsets.symmetric(horizontal: 4.0), - clampDouble(MediaQuery.textScalerOf(context).textScaleFactor - 1.0, 0.0, 1.0), - )!; + EdgeInsetsGeometry? get labelPadding { + final double fontSize = labelStyle?.fontSize ?? 14.0; + final double fontSizeRatio = MediaQuery.textScalerOf(context).scale(fontSize) / 14.0; + return EdgeInsets.lerp( + const EdgeInsets.symmetric(horizontal: 8.0), + const EdgeInsets.symmetric(horizontal: 4.0), + clampDouble(fontSizeRatio - 1.0, 0.0, 1.0), + )!; + } } '''; } diff --git a/dev/tools/gen_defaults/lib/chip_template.dart b/dev/tools/gen_defaults/lib/chip_template.dart index 4d9383399d..5341bac329 100644 --- a/dev/tools/gen_defaults/lib/chip_template.dart +++ b/dev/tools/gen_defaults/lib/chip_template.dart @@ -62,16 +62,24 @@ class _${blockName}DefaultsM3 extends ChipThemeData { @override EdgeInsetsGeometry? get padding => const EdgeInsets.all(8.0); - /// The chip at text scale 1 starts with 8px on each side and as text scaling - /// gets closer to 2, the label padding is linearly interpolated from 8px to 4px. - /// Once the widget has a text scaling of 2 or higher than the label padding - /// remains 4px. + /// The label padding of the chip scales with the font size specified in the + /// [labelStyle], and the system font size settings that scale font sizes + /// globally. + /// + /// The chip at effective font size 14.0 starts with 8px on each side and as + /// the font size scales up to closer to 28.0, the label padding is linearly + /// interpolated from 8px to 4px. Once the label has a font size of 2 or + /// higher, label padding remains 4px. @override - EdgeInsetsGeometry? get labelPadding => EdgeInsets.lerp( - const EdgeInsets.symmetric(horizontal: 8.0), - const EdgeInsets.symmetric(horizontal: 4.0), - clampDouble(MediaQuery.textScalerOf(context).textScaleFactor - 1.0, 0.0, 1.0), - )!; + EdgeInsetsGeometry? get labelPadding { + final double fontSize = labelStyle?.fontSize ?? 14.0; + final double fontSizeRatio = MediaQuery.textScalerOf(context).scale(fontSize) / 14.0; + return EdgeInsets.lerp( + const EdgeInsets.symmetric(horizontal: 8.0), + const EdgeInsets.symmetric(horizontal: 4.0), + clampDouble(fontSizeRatio - 1.0, 0.0, 1.0), + )!; + } } '''; } diff --git a/dev/tools/gen_defaults/lib/filter_chip_template.dart b/dev/tools/gen_defaults/lib/filter_chip_template.dart index d13cba9cff..93d4ad0e09 100644 --- a/dev/tools/gen_defaults/lib/filter_chip_template.dart +++ b/dev/tools/gen_defaults/lib/filter_chip_template.dart @@ -100,16 +100,24 @@ class _${blockName}DefaultsM3 extends ChipThemeData { @override EdgeInsetsGeometry? get padding => const EdgeInsets.all(8.0); - /// The chip at text scale 1 starts with 8px on each side and as text scaling - /// gets closer to 2 the label padding is linearly interpolated from 8px to 4px. - /// Once the widget has a text scaling of 2 or higher than the label padding - /// remains 4px. + /// The label padding of the chip scales with the font size specified in the + /// [labelStyle], and the system font size settings that scale font sizes + /// globally. + /// + /// The chip at effective font size 14.0 starts with 8px on each side and as + /// the font size scales up to closer to 28.0, the label padding is linearly + /// interpolated from 8px to 4px. Once the label has a font size of 2 or + /// higher, label padding remains 4px. @override - EdgeInsetsGeometry? get labelPadding => EdgeInsets.lerp( - const EdgeInsets.symmetric(horizontal: 8.0), - const EdgeInsets.symmetric(horizontal: 4.0), - clampDouble(MediaQuery.textScalerOf(context).textScaleFactor - 1.0, 0.0, 1.0), - )!; + EdgeInsetsGeometry? get labelPadding { + final double fontSize = labelStyle?.fontSize ?? 14.0; + final double fontSizeRatio = MediaQuery.textScalerOf(context).scale(fontSize) / 14.0; + return EdgeInsets.lerp( + const EdgeInsets.symmetric(horizontal: 8.0), + const EdgeInsets.symmetric(horizontal: 4.0), + clampDouble(fontSizeRatio - 1.0, 0.0, 1.0), + )!; + } } '''; } diff --git a/dev/tools/gen_defaults/lib/input_chip_template.dart b/dev/tools/gen_defaults/lib/input_chip_template.dart index 529113cbbf..d6e4e123e5 100644 --- a/dev/tools/gen_defaults/lib/input_chip_template.dart +++ b/dev/tools/gen_defaults/lib/input_chip_template.dart @@ -77,16 +77,24 @@ class _${blockName}DefaultsM3 extends ChipThemeData { @override EdgeInsetsGeometry? get padding => const EdgeInsets.all(8.0); - /// The chip at text scale 1 starts with 8px on each side and as text scaling - /// gets closer to 2 the label padding is linearly interpolated from 8px to 4px. - /// Once the widget has a text scaling of 2 or higher than the label padding - /// remains 4px. + /// The label padding of the chip scales with the font size specified in the + /// [labelStyle], and the system font size settings that scale font sizes + /// globally. + /// + /// The chip at effective font size 14.0 starts with 8px on each side and as + /// the font size scales up to closer to 28.0, the label padding is linearly + /// interpolated from 8px to 4px. Once the label has a font size of 2 or + /// higher, label padding remains 4px. @override - EdgeInsetsGeometry? get labelPadding => EdgeInsets.lerp( - const EdgeInsets.symmetric(horizontal: 8.0), - const EdgeInsets.symmetric(horizontal: 4.0), - clampDouble(MediaQuery.textScalerOf(context).textScaleFactor - 1.0, 0.0, 1.0), - )!; + EdgeInsetsGeometry? get labelPadding { + final double fontSize = labelStyle?.fontSize ?? 14.0; + final double fontSizeRatio = MediaQuery.textScalerOf(context).scale(fontSize) / 14.0; + return EdgeInsets.lerp( + const EdgeInsets.symmetric(horizontal: 8.0), + const EdgeInsets.symmetric(horizontal: 4.0), + clampDouble(fontSizeRatio - 1.0, 0.0, 1.0), + )!; + } } '''; } diff --git a/dev/tools/gen_defaults/lib/menu_template.dart b/dev/tools/gen_defaults/lib/menu_template.dart index 6d2d6b4430..cb09087d8d 100644 --- a/dev/tools/gen_defaults/lib/menu_template.dart +++ b/dev/tools/gen_defaults/lib/menu_template.dart @@ -200,6 +200,11 @@ class _MenuButtonDefaultsM3 extends ButtonStyle { if (visualDensity.horizontal > 0) { visualDensity = VisualDensity(vertical: visualDensity.vertical); } + // Since the threshold paddings used below are empirical values determined + // at a font size of 14.0, 14.0 is used as the base value for scaling the + // padding. + final double fontSize = Theme.of(context).textTheme.labelLarge?.fontSize ?? 14.0; + final double fontSizeRatio = MediaQuery.textScalerOf(context).scale(fontSize) / 14.0; return ButtonStyleButton.scaledPadding( EdgeInsets.symmetric(horizontal: math.max( _kMenuViewPadding, @@ -210,7 +215,7 @@ class _MenuButtonDefaultsM3 extends ButtonStyle { 8 + visualDensity.baseSizeAdjustment.dx, )), const EdgeInsets.symmetric(horizontal: _kMenuViewPadding), - MediaQuery.maybeTextScaleFactorOf(context) ?? 1, + fontSizeRatio, ); } } diff --git a/packages/flutter/lib/src/cupertino/dialog.dart b/packages/flutter/lib/src/cupertino/dialog.dart index 16dc69b85c..6e0c22997c 100644 --- a/packages/flutter/lib/src/cupertino/dialog.dart +++ b/packages/flutter/lib/src/cupertino/dialog.dart @@ -149,8 +149,9 @@ const double _kMaxRegularTextScaleFactor = 1.4; // Accessibility mode on iOS is determined by the text scale factor that the // user has selected. bool _isInAccessibilityMode(BuildContext context) { - final double? factor = MediaQuery.maybeTextScalerOf(context)?.textScaleFactor; - return factor != null && factor > _kMaxRegularTextScaleFactor; + const double defaultFontSize = 14.0; + final double? scaledFontSize = MediaQuery.maybeTextScalerOf(context)?.scale(defaultFontSize); + return scaledFontSize != null && scaledFontSize > defaultFontSize * _kMaxRegularTextScaleFactor; } /// An iOS-style alert dialog. @@ -264,7 +265,8 @@ class _CupertinoAlertDialogState extends State { widget.actionScrollController ?? (_backupActionScrollController ??= ScrollController()); Widget _buildContent(BuildContext context) { - final double textScaleFactor = MediaQuery.textScalerOf(context).textScaleFactor; + const double defaultFontSize = 14.0; + final double effectiveTextScaleFactor = MediaQuery.textScalerOf(context).scale(defaultFontSize) / defaultFontSize; final List children = [ if (widget.title != null || widget.content != null) @@ -278,12 +280,12 @@ class _CupertinoAlertDialogState extends State { left: _kDialogEdgePadding, right: _kDialogEdgePadding, bottom: widget.content == null ? _kDialogEdgePadding : 1.0, - top: _kDialogEdgePadding * textScaleFactor, + top: _kDialogEdgePadding * effectiveTextScaleFactor, ), messagePadding: EdgeInsets.only( left: _kDialogEdgePadding, right: _kDialogEdgePadding, - bottom: _kDialogEdgePadding * textScaleFactor, + bottom: _kDialogEdgePadding * effectiveTextScaleFactor, top: widget.title == null ? _kDialogEdgePadding : 1.0, ), titleTextStyle: _kCupertinoDialogTitleStyle.copyWith( @@ -1653,10 +1655,6 @@ class CupertinoDialogAction extends StatelessWidget { /// value. bool get enabled => onPressed != null; - double _calculatePadding(BuildContext context) { - return 8.0 * MediaQuery.textScalerOf(context).textScaleFactor; - } - // Dialog action content shrinks to fit, up to a certain point, and if it still // cannot fit at the minimum size, the text content is ellipsized. // @@ -1665,6 +1663,7 @@ class CupertinoDialogAction extends StatelessWidget { required BuildContext context, required TextStyle textStyle, required Widget content, + required double padding, }) { final bool isInAccessibilityMode = _isInAccessibilityMode(context); final double dialogWidth = isInAccessibilityMode @@ -1675,7 +1674,6 @@ class CupertinoDialogAction extends StatelessWidget { // buttons. This ratio information is used to automatically scale down action // button text to fit the available space. final double fontSizeRatio = MediaQuery.textScalerOf(context).scale(textStyle.fontSize!) / _kDialogMinButtonFontSize; - final double padding = _calculatePadding(context); return IntrinsicHeight( child: SizedBox( @@ -1724,8 +1722,7 @@ class CupertinoDialogAction extends StatelessWidget { isDestructiveAction ? CupertinoColors.systemRed : CupertinoTheme.of(context).primaryColor, context, ), - ); - style = style.merge(textStyle); + ).merge(textStyle); if (isDefaultAction) { style = style.copyWith(fontWeight: FontWeight.w600); @@ -1734,7 +1731,10 @@ class CupertinoDialogAction extends StatelessWidget { if (!enabled) { style = style.copyWith(color: style.color!.withOpacity(0.5)); } - + final double fontSize = style.fontSize ?? kDefaultFontSize; + final double fontSizeToScale = fontSize == 0.0 ? kDefaultFontSize : fontSize; + final double effectiveTextScale = MediaQuery.textScalerOf(context).scale(fontSizeToScale) / fontSizeToScale; + final double padding = 8.0 * effectiveTextScale; // Apply a sizing policy to the action button's content based on whether or // not the device is in accessibility mode. // TODO(mattcarroll): The following logic is not entirely correct. It is also @@ -1750,6 +1750,7 @@ class CupertinoDialogAction extends StatelessWidget { context: context, textStyle: style, content: child, + padding: padding, ); return MouseRegion( @@ -1764,7 +1765,7 @@ class CupertinoDialogAction extends StatelessWidget { ), child: Container( alignment: Alignment.center, - padding: EdgeInsets.all(_calculatePadding(context)), + padding: EdgeInsets.all(padding), child: sizedContent, ), ), diff --git a/packages/flutter/lib/src/cupertino/search_field.dart b/packages/flutter/lib/src/cupertino/search_field.dart index 2ef0bbd786..be24e3a622 100644 --- a/packages/flutter/lib/src/cupertino/search_field.dart +++ b/packages/flutter/lib/src/cupertino/search_field.dart @@ -408,7 +408,7 @@ class _CupertinoSearchTextFieldState extends State // The icon size will be scaled by a factor of the accessibility text scale, // to follow the behavior of `UISearchTextField`. - final double scaledIconSize = MediaQuery.textScalerOf(context).textScaleFactor * widget.itemSize; + final double scaledIconSize = MediaQuery.textScalerOf(context).scale(widget.itemSize); // If decoration was not provided, create a decoration with the provided // background color and border radius. diff --git a/packages/flutter/lib/src/material/action_chip.dart b/packages/flutter/lib/src/material/action_chip.dart index ab773e90b9..0d4bec3f7b 100644 --- a/packages/flutter/lib/src/material/action_chip.dart +++ b/packages/flutter/lib/src/material/action_chip.dart @@ -304,16 +304,24 @@ class _ActionChipDefaultsM3 extends ChipThemeData { @override EdgeInsetsGeometry? get padding => const EdgeInsets.all(8.0); - /// The chip at text scale 1 starts with 8px on each side and as text scaling - /// gets closer to 2 the label padding is linearly interpolated from 8px to 4px. - /// Once the widget has a text scaling of 2 or higher than the label padding - /// remains 4px. + /// The label padding of the chip scales with the font size specified in the + /// [labelStyle], and the system font size settings that scale font sizes + /// globally. + /// + /// The chip at effective font size 14.0 starts with 8px on each side and as + /// the font size scales up to closer to 28.0, the label padding is linearly + /// interpolated from 8px to 4px. Once the label has a font size of 2 or + /// higher, label padding remains 4px. @override - EdgeInsetsGeometry? get labelPadding => EdgeInsets.lerp( - const EdgeInsets.symmetric(horizontal: 8.0), - const EdgeInsets.symmetric(horizontal: 4.0), - clampDouble(MediaQuery.textScalerOf(context).textScaleFactor - 1.0, 0.0, 1.0), - )!; + EdgeInsetsGeometry? get labelPadding { + final double fontSize = labelStyle?.fontSize ?? 14.0; + final double fontSizeRatio = MediaQuery.textScalerOf(context).scale(fontSize) / 14.0; + return EdgeInsets.lerp( + const EdgeInsets.symmetric(horizontal: 8.0), + const EdgeInsets.symmetric(horizontal: 4.0), + clampDouble(fontSizeRatio - 1.0, 0.0, 1.0), + )!; + } } // END GENERATED TOKEN PROPERTIES - ActionChip diff --git a/packages/flutter/lib/src/material/chip.dart b/packages/flutter/lib/src/material/chip.dart index 51ac6de9e2..db91a12477 100644 --- a/packages/flutter/lib/src/material/chip.dart +++ b/packages/flutter/lib/src/material/chip.dart @@ -1158,16 +1158,6 @@ class _RawChipState extends State with MaterialStateMixin, TickerProvid assert(debugCheckHasDirectionality(context)); assert(debugCheckHasMaterialLocalizations(context)); - /// The chip at text scale 1 starts with 8px on each side and as text scaling - /// gets closer to 2 the label padding is linearly interpolated from 8px to 4px. - /// Once the widget has a text scaling of 2 or higher than the label padding - /// remains 4px. - final EdgeInsetsGeometry defaultLabelPadding = EdgeInsets.lerp( - const EdgeInsets.symmetric(horizontal: 8.0), - const EdgeInsets.symmetric(horizontal: 4.0), - clampDouble(MediaQuery.textScalerOf(context).textScaleFactor - 1.0, 0.0, 1.0), - )!; - final ThemeData theme = Theme.of(context); final ChipThemeData chipTheme = ChipTheme.of(context); final Brightness brightness = chipTheme.brightness ?? theme.brightness; @@ -1212,10 +1202,6 @@ class _RawChipState extends State with MaterialStateMixin, TickerProvid // Widget's label style is merged with this below. final TextStyle labelStyle = chipTheme.labelStyle ?? chipDefaults.labelStyle!; - final EdgeInsetsGeometry labelPadding = widget.labelPadding - ?? chipTheme.labelPadding - ?? chipDefaults.labelPadding - ?? defaultLabelPadding; final IconThemeData? iconTheme = widget.iconTheme ?? chipTheme.iconTheme ?? chipDefaults.iconTheme; @@ -1230,6 +1216,23 @@ class _RawChipState extends State with MaterialStateMixin, TickerProvid ) : widget.avatar; + /// The chip at text scale 1 starts with 8px on each side and as text scaling + /// gets closer to 2 the label padding is linearly interpolated from 8px to 4px. + /// Once the widget has a text scaling of 2 or higher than the label padding + /// remains 4px. + final double defaultFontSize = effectiveLabelStyle.fontSize ?? 14.0; + final double effectiveTextScale = MediaQuery.textScalerOf(context).scale(defaultFontSize) / 14.0; + final EdgeInsetsGeometry defaultLabelPadding = EdgeInsets.lerp( + const EdgeInsets.symmetric(horizontal: 8.0), + const EdgeInsets.symmetric(horizontal: 4.0), + clampDouble(effectiveTextScale - 1.0, 0.0, 1.0), + )!; + + final EdgeInsetsGeometry labelPadding = widget.labelPadding + ?? chipTheme.labelPadding + ?? chipDefaults.labelPadding + ?? defaultLabelPadding; + Widget result = Material( elevation: isTapping ? pressElevation : elevation, shadowColor: widget.selected ? selectedShadowColor : shadowColor, @@ -2319,16 +2322,24 @@ class _ChipDefaultsM3 extends ChipThemeData { @override EdgeInsetsGeometry? get padding => const EdgeInsets.all(8.0); - /// The chip at text scale 1 starts with 8px on each side and as text scaling - /// gets closer to 2, the label padding is linearly interpolated from 8px to 4px. - /// Once the widget has a text scaling of 2 or higher than the label padding - /// remains 4px. + /// The label padding of the chip scales with the font size specified in the + /// [labelStyle], and the system font size settings that scale font sizes + /// globally. + /// + /// The chip at effective font size 14.0 starts with 8px on each side and as + /// the font size scales up to closer to 28.0, the label padding is linearly + /// interpolated from 8px to 4px. Once the label has a font size of 2 or + /// higher, label padding remains 4px. @override - EdgeInsetsGeometry? get labelPadding => EdgeInsets.lerp( - const EdgeInsets.symmetric(horizontal: 8.0), - const EdgeInsets.symmetric(horizontal: 4.0), - clampDouble(MediaQuery.textScalerOf(context).textScaleFactor - 1.0, 0.0, 1.0), - )!; + EdgeInsetsGeometry? get labelPadding { + final double fontSize = labelStyle?.fontSize ?? 14.0; + final double fontSizeRatio = MediaQuery.textScalerOf(context).scale(fontSize) / 14.0; + return EdgeInsets.lerp( + const EdgeInsets.symmetric(horizontal: 8.0), + const EdgeInsets.symmetric(horizontal: 4.0), + clampDouble(fontSizeRatio - 1.0, 0.0, 1.0), + )!; + } } // END GENERATED TOKEN PROPERTIES - Chip diff --git a/packages/flutter/lib/src/material/choice_chip.dart b/packages/flutter/lib/src/material/choice_chip.dart index 873d554199..8f68e03c51 100644 --- a/packages/flutter/lib/src/material/choice_chip.dart +++ b/packages/flutter/lib/src/material/choice_chip.dart @@ -329,16 +329,24 @@ class _ChoiceChipDefaultsM3 extends ChipThemeData { @override EdgeInsetsGeometry? get padding => const EdgeInsets.all(8.0); - /// The chip at text scale 1 starts with 8px on each side and as text scaling - /// gets closer to 2 the label padding is linearly interpolated from 8px to 4px. - /// Once the widget has a text scaling of 2 or higher than the label padding - /// remains 4px. + /// The label padding of the chip scales with the font size specified in the + /// [labelStyle], and the system font size settings that scale font sizes + /// globally. + /// + /// The chip at effective font size 14.0 starts with 8px on each side and as + /// the font size scales up to closer to 28.0, the label padding is linearly + /// interpolated from 8px to 4px. Once the label has a font size of 2 or + /// higher, label padding remains 4px. @override - EdgeInsetsGeometry? get labelPadding => EdgeInsets.lerp( - const EdgeInsets.symmetric(horizontal: 8.0), - const EdgeInsets.symmetric(horizontal: 4.0), - clampDouble(MediaQuery.textScalerOf(context).textScaleFactor - 1.0, 0.0, 1.0), - )!; + EdgeInsetsGeometry? get labelPadding { + final double fontSize = labelStyle?.fontSize ?? 14.0; + final double fontSizeRatio = MediaQuery.textScalerOf(context).scale(fontSize) / 14.0; + return EdgeInsets.lerp( + const EdgeInsets.symmetric(horizontal: 8.0), + const EdgeInsets.symmetric(horizontal: 4.0), + clampDouble(fontSizeRatio - 1.0, 0.0, 1.0), + )!; + } } // END GENERATED TOKEN PROPERTIES - ChoiceChip diff --git a/packages/flutter/lib/src/material/date_picker.dart b/packages/flutter/lib/src/material/date_picker.dart index 9681370a52..3056c7480c 100644 --- a/packages/flutter/lib/src/material/date_picker.dart +++ b/packages/flutter/lib/src/material/date_picker.dart @@ -659,7 +659,9 @@ class _DatePickerDialogState extends State with RestorationMix // Constrain the textScaleFactor to the largest supported value to prevent // layout issues. - final double textScaleFactor = MediaQuery.textScalerOf(context).clamp(maxScaleFactor: _kMaxTextScaleFactor).textScaleFactor; + // 14 is a common font size used to compute the effective text scale. + const double fontSizeToScale = 14.0; + final double textScaleFactor = MediaQuery.textScalerOf(context).clamp(maxScaleFactor: _kMaxTextScaleFactor).scale(fontSizeToScale) / fontSizeToScale; final Size dialogSize = _dialogSize(context) * textScaleFactor; final DialogTheme dialogTheme = theme.dialogTheme; return Dialog( @@ -2874,7 +2876,9 @@ class _InputDateRangePickerDialog extends StatelessWidget { ), ); - final double textScaleFactor = MediaQuery.textScalerOf(context).clamp(maxScaleFactor: _kMaxTextScaleFactor).textScaleFactor; + // 14 is a common font size used to compute the effective text scale. + const double fontSizeToScale = 14.0; + final double textScaleFactor = MediaQuery.textScalerOf(context).clamp(maxScaleFactor: _kMaxTextScaleFactor).scale(fontSizeToScale) / fontSizeToScale; final Size dialogSize = (useMaterial3 ? _inputPortraitDialogSizeM3 : _inputPortraitDialogSizeM2) * textScaleFactor; switch (orientation) { case Orientation.portrait: diff --git a/packages/flutter/lib/src/material/dialog.dart b/packages/flutter/lib/src/material/dialog.dart index a9ca87452c..5d06b651fc 100644 --- a/packages/flutter/lib/src/material/dialog.dart +++ b/packages/flutter/lib/src/material/dialog.dart @@ -718,7 +718,9 @@ class AlertDialog extends StatelessWidget { // The paddingScaleFactor is used to adjust the padding of Dialog's // children. - final double paddingScaleFactor = _paddingScaleFactor(MediaQuery.textScalerOf(context).textScaleFactor); + const double fontSizeToScale = 14.0; + final double effectiveTextScale = MediaQuery.textScalerOf(context).scale(fontSizeToScale) / fontSizeToScale; + final double paddingScaleFactor = _scalePadding(effectiveTextScale); final TextDirection? textDirection = Directionality.maybeOf(context); Widget? iconWidget; @@ -1213,7 +1215,11 @@ class SimpleDialog extends StatelessWidget { // The paddingScaleFactor is used to adjust the padding of Dialog // children. - final double paddingScaleFactor = _paddingScaleFactor(MediaQuery.textScalerOf(context).textScaleFactor); + final TextStyle defaultTextStyle = titleTextStyle ?? DialogTheme.of(context).titleTextStyle ?? theme.textTheme.titleLarge!; + final double fontSize = defaultTextStyle.fontSize ?? kDefaultFontSize; + final double fontSizeToScale = fontSize == 0.0 ? kDefaultFontSize : fontSize; + final double effectiveTextScale = MediaQuery.textScalerOf(context).scale(fontSizeToScale) / fontSizeToScale; + final double paddingScaleFactor = _scalePadding(effectiveTextScale); final TextDirection? textDirection = Directionality.maybeOf(context); Widget? titleWidget; @@ -1227,7 +1233,7 @@ class SimpleDialog extends StatelessWidget { bottom: children == null ? effectiveTitlePadding.bottom * paddingScaleFactor : effectiveTitlePadding.bottom, ), child: DefaultTextStyle( - style: titleTextStyle ?? DialogTheme.of(context).titleTextStyle ?? theme.textTheme.titleLarge!, + style: defaultTextStyle, child: Semantics( // For iOS platform, the focus always lands on the title. // Set nameRoute to false to avoid title being announce twice. @@ -1577,7 +1583,7 @@ class DialogRoute extends RawDialogRoute { ); } -double _paddingScaleFactor(double textScaleFactor) { +double _scalePadding(double textScaleFactor) { final double clampedTextScaleFactor = clampDouble(textScaleFactor, 1.0, 2.0); // The final padding scale factor is clamped between 1/3 and 1. For example, // a non-scaled padding of 24 will produce a padding between 24 and 8. diff --git a/packages/flutter/lib/src/material/elevated_button.dart b/packages/flutter/lib/src/material/elevated_button.dart index f91c9a0928..1f83100ab0 100644 --- a/packages/flutter/lib/src/material/elevated_button.dart +++ b/packages/flutter/lib/src/material/elevated_button.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:math' as math; import 'dart:ui' show lerpDouble; import 'package:flutter/foundation.dart'; @@ -483,7 +482,7 @@ class _ElevatedButtonWithIcon extends ElevatedButton { }) : super( autofocus: autofocus ?? false, clipBehavior: clipBehavior ?? Clip.none, - child: _ElevatedButtonWithIconChild(icon: icon, label: label), + child: _ElevatedButtonWithIconChild(icon: icon, label: label, buttonStyle: style), ); @override @@ -512,15 +511,17 @@ class _ElevatedButtonWithIcon extends ElevatedButton { } class _ElevatedButtonWithIconChild extends StatelessWidget { - const _ElevatedButtonWithIconChild({ required this.label, required this.icon }); + const _ElevatedButtonWithIconChild({ required this.label, required this.icon, required this.buttonStyle }); final Widget label; final Widget icon; + final ButtonStyle? buttonStyle; @override Widget build(BuildContext context) { - final double scale = MediaQuery.textScalerOf(context).textScaleFactor; - final double gap = scale <= 1 ? 8 : lerpDouble(8, 4, math.min(scale - 1, 1))!; + final double defaultFontSize = buttonStyle?.textStyle?.resolve(const {})?.fontSize ?? 14.0; + final double scale = clampDouble(MediaQuery.textScalerOf(context).scale(defaultFontSize) / 14.0, 1.0, 2.0) - 1.0; + final double gap = lerpDouble(8, 4, scale)!; return Row( mainAxisSize: MainAxisSize.min, children: [icon, SizedBox(width: gap), Flexible(child: label)], diff --git a/packages/flutter/lib/src/material/filled_button.dart b/packages/flutter/lib/src/material/filled_button.dart index b1772b4d17..09dc8d7575 100644 --- a/packages/flutter/lib/src/material/filled_button.dart +++ b/packages/flutter/lib/src/material/filled_button.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:math' as math; import 'dart:ui' show lerpDouble; import 'package:flutter/foundation.dart'; @@ -476,7 +475,7 @@ class _FilledButtonWithIcon extends FilledButton { }) : super( autofocus: autofocus ?? false, clipBehavior: clipBehavior ?? Clip.none, - child: _FilledButtonWithIconChild(icon: icon, label: label) + child: _FilledButtonWithIconChild(icon: icon, label: label, buttonStyle: style), ); _FilledButtonWithIcon.tonal({ @@ -495,7 +494,7 @@ class _FilledButtonWithIcon extends FilledButton { }) : super.tonal( autofocus: autofocus ?? false, clipBehavior: clipBehavior ?? Clip.none, - child: _FilledButtonWithIconChild(icon: icon, label: label) + child: _FilledButtonWithIconChild(icon: icon, label: label, buttonStyle: style), ); @override @@ -524,17 +523,19 @@ class _FilledButtonWithIcon extends FilledButton { } class _FilledButtonWithIconChild extends StatelessWidget { - const _FilledButtonWithIconChild({ required this.label, required this.icon }); + const _FilledButtonWithIconChild({ required this.label, required this.icon, required this.buttonStyle }); final Widget label; final Widget icon; + final ButtonStyle? buttonStyle; @override Widget build(BuildContext context) { - final double scale = MediaQuery.textScalerOf(context).textScaleFactor; + final double defaultFontSize = buttonStyle?.textStyle?.resolve(const {})?.fontSize ?? 14.0; + final double scale = clampDouble(MediaQuery.textScalerOf(context).scale(defaultFontSize) / 14.0, 1.0, 2.0) - 1.0; // Adjust the gap based on the text scale factor. Start at 8, and lerp // to 4 based on how large the text is. - final double gap = scale <= 1 ? 8 : lerpDouble(8, 4, math.min(scale - 1, 1))!; + final double gap = lerpDouble(8, 4, scale)!; return Row( mainAxisSize: MainAxisSize.min, children: [icon, SizedBox(width: gap), Flexible(child: label)], diff --git a/packages/flutter/lib/src/material/filter_chip.dart b/packages/flutter/lib/src/material/filter_chip.dart index 7770cf23b8..d0a495a02d 100644 --- a/packages/flutter/lib/src/material/filter_chip.dart +++ b/packages/flutter/lib/src/material/filter_chip.dart @@ -355,16 +355,24 @@ class _FilterChipDefaultsM3 extends ChipThemeData { @override EdgeInsetsGeometry? get padding => const EdgeInsets.all(8.0); - /// The chip at text scale 1 starts with 8px on each side and as text scaling - /// gets closer to 2 the label padding is linearly interpolated from 8px to 4px. - /// Once the widget has a text scaling of 2 or higher than the label padding - /// remains 4px. + /// The label padding of the chip scales with the font size specified in the + /// [labelStyle], and the system font size settings that scale font sizes + /// globally. + /// + /// The chip at effective font size 14.0 starts with 8px on each side and as + /// the font size scales up to closer to 28.0, the label padding is linearly + /// interpolated from 8px to 4px. Once the label has a font size of 2 or + /// higher, label padding remains 4px. @override - EdgeInsetsGeometry? get labelPadding => EdgeInsets.lerp( - const EdgeInsets.symmetric(horizontal: 8.0), - const EdgeInsets.symmetric(horizontal: 4.0), - clampDouble(MediaQuery.textScalerOf(context).textScaleFactor - 1.0, 0.0, 1.0), - )!; + EdgeInsetsGeometry? get labelPadding { + final double fontSize = labelStyle?.fontSize ?? 14.0; + final double fontSizeRatio = MediaQuery.textScalerOf(context).scale(fontSize) / 14.0; + return EdgeInsets.lerp( + const EdgeInsets.symmetric(horizontal: 8.0), + const EdgeInsets.symmetric(horizontal: 4.0), + clampDouble(fontSizeRatio - 1.0, 0.0, 1.0), + )!; + } } // END GENERATED TOKEN PROPERTIES - FilterChip diff --git a/packages/flutter/lib/src/material/input_chip.dart b/packages/flutter/lib/src/material/input_chip.dart index d3f7ba26dd..ba21514195 100644 --- a/packages/flutter/lib/src/material/input_chip.dart +++ b/packages/flutter/lib/src/material/input_chip.dart @@ -310,16 +310,24 @@ class _InputChipDefaultsM3 extends ChipThemeData { @override EdgeInsetsGeometry? get padding => const EdgeInsets.all(8.0); - /// The chip at text scale 1 starts with 8px on each side and as text scaling - /// gets closer to 2 the label padding is linearly interpolated from 8px to 4px. - /// Once the widget has a text scaling of 2 or higher than the label padding - /// remains 4px. + /// The label padding of the chip scales with the font size specified in the + /// [labelStyle], and the system font size settings that scale font sizes + /// globally. + /// + /// The chip at effective font size 14.0 starts with 8px on each side and as + /// the font size scales up to closer to 28.0, the label padding is linearly + /// interpolated from 8px to 4px. Once the label has a font size of 2 or + /// higher, label padding remains 4px. @override - EdgeInsetsGeometry? get labelPadding => EdgeInsets.lerp( - const EdgeInsets.symmetric(horizontal: 8.0), - const EdgeInsets.symmetric(horizontal: 4.0), - clampDouble(MediaQuery.textScalerOf(context).textScaleFactor - 1.0, 0.0, 1.0), - )!; + EdgeInsetsGeometry? get labelPadding { + final double fontSize = labelStyle?.fontSize ?? 14.0; + final double fontSizeRatio = MediaQuery.textScalerOf(context).scale(fontSize) / 14.0; + return EdgeInsets.lerp( + const EdgeInsets.symmetric(horizontal: 8.0), + const EdgeInsets.symmetric(horizontal: 4.0), + clampDouble(fontSizeRatio - 1.0, 0.0, 1.0), + )!; + } } // END GENERATED TOKEN PROPERTIES - InputChip diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart index 85a3b90db1..b6440a26ee 100644 --- a/packages/flutter/lib/src/material/input_decorator.dart +++ b/packages/flutter/lib/src/material/input_decorator.dart @@ -2416,7 +2416,7 @@ class _InputDecoratorState extends State with TickerProviderStat contentPadding = decorationContentPadding ?? EdgeInsets.zero; } else if (!border.isOutline) { // 4.0: the vertical gap between the inline elements and the floating label. - floatingLabelHeight = (4.0 + 0.75 * labelStyle.fontSize!) * MediaQuery.textScalerOf(context).textScaleFactor; + floatingLabelHeight = MediaQuery.textScalerOf(context).scale(4.0 + 0.75 * labelStyle.fontSize!); if (decoration.filled ?? false) { contentPadding = decorationContentPadding ?? (decorationIsDense ? const EdgeInsets.fromLTRB(12.0, 8.0, 12.0, 8.0) diff --git a/packages/flutter/lib/src/material/menu_anchor.dart b/packages/flutter/lib/src/material/menu_anchor.dart index e2e602aee0..45c292259b 100644 --- a/packages/flutter/lib/src/material/menu_anchor.dart +++ b/packages/flutter/lib/src/material/menu_anchor.dart @@ -3903,6 +3903,11 @@ class _MenuButtonDefaultsM3 extends ButtonStyle { if (visualDensity.horizontal > 0) { visualDensity = VisualDensity(vertical: visualDensity.vertical); } + // Since the threshold paddings used below are empirical values determined + // at a font size of 14.0, 14.0 is used as the base value for scaling the + // padding. + final double fontSize = Theme.of(context).textTheme.labelLarge?.fontSize ?? 14.0; + final double fontSizeRatio = MediaQuery.textScalerOf(context).scale(fontSize) / 14.0; return ButtonStyleButton.scaledPadding( EdgeInsets.symmetric(horizontal: math.max( _kMenuViewPadding, @@ -3913,7 +3918,7 @@ class _MenuButtonDefaultsM3 extends ButtonStyle { 8 + visualDensity.baseSizeAdjustment.dx, )), const EdgeInsets.symmetric(horizontal: _kMenuViewPadding), - MediaQuery.maybeTextScaleFactorOf(context) ?? 1, + fontSizeRatio, ); } } diff --git a/packages/flutter/lib/src/material/outlined_button.dart b/packages/flutter/lib/src/material/outlined_button.dart index e25cc4bb8b..e467e1b312 100644 --- a/packages/flutter/lib/src/material/outlined_button.dart +++ b/packages/flutter/lib/src/material/outlined_button.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:math' as math; import 'dart:ui' show lerpDouble; import 'package:flutter/foundation.dart'; @@ -414,7 +413,7 @@ class _OutlinedButtonWithIcon extends OutlinedButton { }) : super( autofocus: autofocus ?? false, clipBehavior: clipBehavior ?? Clip.none, - child: _OutlinedButtonWithIconChild(icon: icon, label: label), + child: _OutlinedButtonWithIconChild(icon: icon, label: label, buttonStyle: style), ); @override @@ -442,15 +441,18 @@ class _OutlinedButtonWithIconChild extends StatelessWidget { const _OutlinedButtonWithIconChild({ required this.label, required this.icon, + required this.buttonStyle, }); final Widget label; final Widget icon; + final ButtonStyle? buttonStyle; @override Widget build(BuildContext context) { - final double scale = MediaQuery.textScalerOf(context).textScaleFactor; - final double gap = scale <= 1 ? 8 : lerpDouble(8, 4, math.min(scale - 1, 1))!; + final double defaultFontSize = buttonStyle?.textStyle?.resolve(const {})?.fontSize ?? 14.0; + final double scale = clampDouble(MediaQuery.textScalerOf(context).scale(defaultFontSize) / 14.0, 1.0, 2.0) - 1.0; + final double gap = lerpDouble(8, 4, scale)!; return Row( mainAxisSize: MainAxisSize.min, children: [icon, SizedBox(width: gap), Flexible(child: label)], diff --git a/packages/flutter/lib/src/material/text_button.dart b/packages/flutter/lib/src/material/text_button.dart index 687e2a40e7..3120989810 100644 --- a/packages/flutter/lib/src/material/text_button.dart +++ b/packages/flutter/lib/src/material/text_button.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:math' as math; import 'dart:ui' show lerpDouble; import 'package:flutter/foundation.dart'; @@ -479,7 +478,7 @@ class _TextButtonWithIcon extends TextButton { }) : super( autofocus: autofocus ?? false, clipBehavior: clipBehavior ?? Clip.none, - child: _TextButtonWithIconChild(icon: icon, label: label), + child: _TextButtonWithIconChild(icon: icon, label: label, buttonStyle: style), ); @override @@ -504,15 +503,18 @@ class _TextButtonWithIconChild extends StatelessWidget { const _TextButtonWithIconChild({ required this.label, required this.icon, + required this.buttonStyle, }); final Widget label; final Widget icon; + final ButtonStyle? buttonStyle; @override Widget build(BuildContext context) { - final double scale = MediaQuery.textScalerOf(context).textScaleFactor; - final double gap = scale <= 1 ? 8 : lerpDouble(8, 4, math.min(scale - 1, 1))!; + final double defaultFontSize = buttonStyle?.textStyle?.resolve(const {})?.fontSize ?? 14.0; + final double scale = clampDouble(MediaQuery.textScalerOf(context).scale(defaultFontSize) / 14.0, 1.0, 2.0) - 1.0; + final double gap = lerpDouble(8, 4, scale)!; return Row( mainAxisSize: MainAxisSize.min, children: [icon, SizedBox(width: gap), Flexible(child: label)], diff --git a/packages/flutter/lib/src/material/time_picker.dart b/packages/flutter/lib/src/material/time_picker.dart index ca97ffdb1e..2faf3f620d 100644 --- a/packages/flutter/lib/src/material/time_picker.dart +++ b/packages/flutter/lib/src/material/time_picker.dart @@ -2348,7 +2348,10 @@ class _TimePickerDialogState extends State with RestorationMix // Constrain the textScaleFactor to prevent layout issues. Since only some // parts of the time picker scale up with textScaleFactor, we cap the factor // to 1.1 as that provides enough space to reasonably fit all the content. - final double textScaleFactor = MediaQuery.textScalerOf(context).clamp(maxScaleFactor: 1.1).textScaleFactor; + // + // 14 is a common font size used to compute the effective text scale. + const double fontSizeToScale = 14.0; + final double textScaleFactor = MediaQuery.textScalerOf(context).clamp(maxScaleFactor: 1.1).scale(fontSizeToScale) / fontSizeToScale; final Size timePickerSize; switch (_entryMode.value) { diff --git a/packages/flutter/test/cupertino/action_sheet_test.dart b/packages/flutter/test/cupertino/action_sheet_test.dart index f998199100..c734737da0 100644 --- a/packages/flutter/test/cupertino/action_sheet_test.dart +++ b/packages/flutter/test/cupertino/action_sheet_test.dart @@ -293,8 +293,9 @@ void main() { await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( Builder(builder: (BuildContext context) { - return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: 3.0), + return MediaQuery.withClampedTextScaling( + minScaleFactor: 3.0, + maxScaleFactor: 3.0, child: CupertinoActionSheet( title: const Text('The title'), message: const Text('The message.'), @@ -361,8 +362,9 @@ void main() { createAppWithButtonThatLaunchesActionSheet( Builder(builder: (BuildContext context) { screenHeight = MediaQuery.sizeOf(context).height; - return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: 3.0), + return MediaQuery.withClampedTextScaling( + minScaleFactor: 3.0, + maxScaleFactor: 3.0, child: CupertinoActionSheet( title: const Text('The title'), message: Text('Very long content' * 200), @@ -1039,8 +1041,9 @@ void main() { await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( Builder(builder: (BuildContext context) { - return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: 3.0), + return MediaQuery.withClampedTextScaling( + minScaleFactor: 3.0, + maxScaleFactor: 3.0, child: CupertinoActionSheet( title: const Text('The title'), message: const Text('The message.'), diff --git a/packages/flutter/test/cupertino/dialog_test.dart b/packages/flutter/test/cupertino/dialog_test.dart index 9e1b06b293..24bacd2ffa 100644 --- a/packages/flutter/test/cupertino/dialog_test.dart +++ b/packages/flutter/test/cupertino/dialog_test.dart @@ -302,8 +302,9 @@ void main() { await tester.pumpWidget( createAppWithButtonThatLaunchesDialog( dialogBuilder: (BuildContext context) { - return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: 3.0), + return MediaQuery.withClampedTextScaling( + minScaleFactor: 3.0, + maxScaleFactor: 3.0, child: CupertinoAlertDialog( title: const Text('The Title'), content: Text('Very long content ' * 20), @@ -405,8 +406,9 @@ void main() { await tester.pumpWidget( createAppWithButtonThatLaunchesDialog( dialogBuilder: (BuildContext context) { - return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: 3.0), + return MediaQuery.withClampedTextScaling( + minScaleFactor: 3.0, + maxScaleFactor: 3.0, child: CupertinoAlertDialog( title: const Text('The title'), content: const Text('The content.'), @@ -461,14 +463,12 @@ void main() { }); testWidgets('Title Section is empty, Button section is not empty.', (WidgetTester tester) async { - const double textScaleFactor = 1.0; final ScrollController actionScrollController = ScrollController(); addTearDown(actionScrollController.dispose); await tester.pumpWidget( createAppWithButtonThatLaunchesDialog( dialogBuilder: (BuildContext context) { - return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: textScaleFactor), + return MediaQuery.withNoTextScaling( child: CupertinoAlertDialog( actions: const [ CupertinoDialogAction( @@ -515,14 +515,12 @@ void main() { }); testWidgets('Button section is empty, Title section is not empty.', (WidgetTester tester) async { - const double textScaleFactor = 1.0; final ScrollController scrollController = ScrollController(); addTearDown(scrollController.dispose); await tester.pumpWidget( createAppWithButtonThatLaunchesDialog( dialogBuilder: (BuildContext context) { - return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: textScaleFactor), + return MediaQuery.withNoTextScaling( child: CupertinoAlertDialog( title: const Text('The title'), content: const Text('The content.'), @@ -715,8 +713,9 @@ void main() { await tester.pumpWidget( createAppWithButtonThatLaunchesDialog( dialogBuilder: (BuildContext context) { - return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: 3.0), + return MediaQuery.withClampedTextScaling( + minScaleFactor: 3.0, + maxScaleFactor: 3.0, child: CupertinoAlertDialog( title: const Text('The Title'), content: Text('The message\n' * 20), @@ -1193,8 +1192,9 @@ void main() { createAppWithButtonThatLaunchesDialog( useMaterial3: false, dialogBuilder: (BuildContext context) { - return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: 3.0), + return MediaQuery.withClampedTextScaling( + minScaleFactor: 3.0, + maxScaleFactor: 3.0, child: const RepaintBoundary( child: CupertinoAlertDialog( title: Text('Title'), @@ -1224,8 +1224,9 @@ void main() { createAppWithButtonThatLaunchesDialog( useMaterial3: true, dialogBuilder: (BuildContext context) { - return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: 3.0), + return MediaQuery.withClampedTextScaling( + minScaleFactor: 3.0, + maxScaleFactor: 3.0, child: const RepaintBoundary( child: CupertinoAlertDialog( title: Text('Title'), @@ -1322,14 +1323,12 @@ void main() { testWidgets('Conflicting scrollbars are not applied by ScrollBehavior to CupertinoAlertDialog', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/83819 - const double textScaleFactor = 1.0; final ScrollController actionScrollController = ScrollController(); addTearDown(actionScrollController.dispose); await tester.pumpWidget( createAppWithButtonThatLaunchesDialog( dialogBuilder: (BuildContext context) { - return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: textScaleFactor), + return MediaQuery.withNoTextScaling( child: CupertinoAlertDialog( title: const Text('Test Title'), content: const Text('Test Content'), @@ -1507,8 +1506,9 @@ void main() { await tester.pumpWidget( createAppWithButtonThatLaunchesDialog( dialogBuilder: (BuildContext context) { - return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: 3.0), + return MediaQuery.withClampedTextScaling( + minScaleFactor: 3.0, + maxScaleFactor: 3.0, child: RepaintBoundary( child: CupertinoAlertDialog( title: const Text('Title'), diff --git a/packages/flutter/test/cupertino/material/tab_scaffold_test.dart b/packages/flutter/test/cupertino/material/tab_scaffold_test.dart index 2ccf74c1fe..0688b03ad7 100644 --- a/packages/flutter/test/cupertino/material/tab_scaffold_test.dart +++ b/packages/flutter/test/cupertino/material/tab_scaffold_test.dart @@ -287,8 +287,9 @@ void main() { await tester.pumpWidget( MaterialApp( home: Builder(builder: (BuildContext context) { - return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: 99), + return MediaQuery.withClampedTextScaling( + minScaleFactor: 99, + maxScaleFactor: 99, child: CupertinoTabScaffold( tabBar: CupertinoTabBar( items: List.generate( diff --git a/packages/flutter/test/cupertino/nav_bar_transition_test.dart b/packages/flutter/test/cupertino/nav_bar_transition_test.dart index 1b656d597f..8609b61c9f 100644 --- a/packages/flutter/test/cupertino/nav_bar_transition_test.dart +++ b/packages/flutter/test/cupertino/nav_bar_transition_test.dart @@ -20,14 +20,14 @@ Future startTransitionBetween( String? toTitle, TextDirection textDirection = TextDirection.ltr, CupertinoThemeData? theme, - double textScale = 1.0, + TextScaler textScaler = TextScaler.noScaling, }) async { await tester.pumpWidget( CupertinoApp( theme: theme, builder: (BuildContext context, Widget? navigator) { return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: textScale), + data: MediaQuery.of(context).copyWith(textScaler: textScaler), child: Directionality( textDirection: textDirection, child: navigator!, @@ -1393,11 +1393,13 @@ void main() { }); testWidgets('textScaleFactor is set to 1.0 on transition', (WidgetTester tester) async { - await startTransitionBetween(tester, fromTitle: 'Page 1', textScale: 99); + await startTransitionBetween(tester, fromTitle: 'Page 1', textScaler: const TextScaler.linear(99)); await tester.pump(const Duration(milliseconds: 50)); - expect(tester.firstWidget(flying(tester, find.byType(RichText))).textScaleFactor, 1); + final TextScaler scaler = tester.firstWidget(flying(tester, find.byType(RichText))).textScaler; + final List fontSizes = List.generate(100, (int index) => index / 3 + 1); + expect(fontSizes.map(scaler.scale), fontSizes); }); testWidgets('Back swipe gesture cancels properly with transition', (WidgetTester tester) async { diff --git a/packages/flutter/test/cupertino/scaffold_test.dart b/packages/flutter/test/cupertino/scaffold_test.dart index 2dd4f74dd3..c69e3f5819 100644 --- a/packages/flutter/test/cupertino/scaffold_test.dart +++ b/packages/flutter/test/cupertino/scaffold_test.dart @@ -532,8 +532,9 @@ void main() { await tester.pumpWidget( CupertinoApp( home: Builder(builder: (BuildContext context) { - return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: 99), + return MediaQuery.withClampedTextScaling( + minScaleFactor: 99, + maxScaleFactor: 99, child: const CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( middle: Text('middle'), diff --git a/packages/flutter/test/material/action_chip_test.dart b/packages/flutter/test/material/action_chip_test.dart index 75d7ccec89..e69874d846 100644 --- a/packages/flutter/test/material/action_chip_test.dart +++ b/packages/flutter/test/material/action_chip_test.dart @@ -9,7 +9,7 @@ import 'package:flutter_test/flutter_test.dart'; Widget wrapForChip({ required Widget child, TextDirection textDirection = TextDirection.ltr, - double textScaleFactor = 1.0, + TextScaler textScaler = TextScaler.noScaling, Brightness brightness = Brightness.light, }) { return MaterialApp( @@ -17,7 +17,7 @@ Widget wrapForChip({ home: Directionality( textDirection: textDirection, child: MediaQuery( - data: MediaQueryData(textScaleFactor: textScaleFactor), + data: MediaQueryData(textScaler: textScaler), child: Material(child: child), ), ), diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart index 49d647d766..441e2c966c 100644 --- a/packages/flutter/test/material/app_bar_test.dart +++ b/packages/flutter/test/material/app_bar_test.dart @@ -3119,8 +3119,9 @@ void main() { theme: ThemeData(textTheme: Typography.englishLike2014), home: Builder( builder: (BuildContext context) { - return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: textScaleFactor), + return MediaQuery.withClampedTextScaling( + minScaleFactor: textScaleFactor, + maxScaleFactor: textScaleFactor, child: Scaffold( appBar: AppBar( centerTitle: false, @@ -3166,8 +3167,9 @@ void main() { return Scaffold( appBar: AppBar( centerTitle: centerTitle, - title: MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: textScaleFactor), + title: MediaQuery.withClampedTextScaling( + minScaleFactor: textScaleFactor, + maxScaleFactor: textScaleFactor, child: const Text('Jumbo'), ), ), @@ -5170,8 +5172,9 @@ void main() { Widget buildAppBar({double textScaleFactor = 1.0}) { return MaterialApp( theme: ThemeData(useMaterial3: true), - home: MediaQuery( - data: MediaQueryData(textScaleFactor: textScaleFactor), + home: MediaQuery.withClampedTextScaling( + minScaleFactor: textScaleFactor, + maxScaleFactor: textScaleFactor, child: Material( child: CustomScrollView( slivers: [ @@ -5211,8 +5214,9 @@ void main() { Widget buildAppBar({double textScaleFactor = 1.0}) { return MaterialApp( theme: ThemeData(useMaterial3: true), - home: MediaQuery( - data: MediaQueryData(textScaleFactor: textScaleFactor), + home: MediaQuery.withClampedTextScaling( + minScaleFactor: textScaleFactor, + maxScaleFactor: textScaleFactor, child: Material( child: CustomScrollView( slivers: [ @@ -5249,8 +5253,9 @@ void main() { Widget buildAppBar({double textScaleFactor = 1.0}) { return MaterialApp( theme: ThemeData(useMaterial3: true), - home: MediaQuery( - data: MediaQueryData(textScaleFactor: textScaleFactor), + home: MediaQuery.withClampedTextScaling( + minScaleFactor: textScaleFactor, + maxScaleFactor: textScaleFactor, child: Material( child: CustomScrollView( slivers: [ @@ -5290,8 +5295,9 @@ void main() { Widget buildAppBar({double textScaleFactor = 1.0}) { return MaterialApp( theme: ThemeData(useMaterial3: true), - home: MediaQuery( - data: MediaQueryData(textScaleFactor: textScaleFactor), + home: MediaQuery.withClampedTextScaling( + minScaleFactor: textScaleFactor, + maxScaleFactor: textScaleFactor, child: Material( child: CustomScrollView( slivers: [ diff --git a/packages/flutter/test/material/bottom_navigation_bar_test.dart b/packages/flutter/test/material/bottom_navigation_bar_test.dart index a80164ac42..b9fc12edee 100644 --- a/packages/flutter/test/material/bottom_navigation_bar_test.dart +++ b/packages/flutter/test/material/bottom_navigation_bar_test.dart @@ -1518,8 +1518,9 @@ void main() { expect(shiftingBox.size.height, equals(kBottomNavigationBarHeight)); await tester.pumpWidget( MaterialApp( - home: MediaQuery( - data: const MediaQueryData(textScaleFactor: 2.0), + home: MediaQuery.withClampedTextScaling( + minScaleFactor: 2.0, + maxScaleFactor: 2.0, child: Scaffold( bottomNavigationBar: BottomNavigationBar( items: const [ @@ -1591,8 +1592,9 @@ void main() { await tester.pumpWidget( MaterialApp( - home: MediaQuery( - data: const MediaQueryData(textScaleFactor: 2.0), + home: MediaQuery.withClampedTextScaling( + minScaleFactor: 2.0, + maxScaleFactor: 2.0, child: Scaffold( bottomNavigationBar: BottomNavigationBar( items: const [ @@ -1770,8 +1772,9 @@ void main() { const String label = 'Foo'; Widget buildApp({ required double textScaleFactor }) { - return MediaQuery( - data: MediaQueryData(textScaleFactor: textScaleFactor), + return MediaQuery.withClampedTextScaling( + minScaleFactor: textScaleFactor, + maxScaleFactor: textScaleFactor, child: Localizations( locale: const Locale('en', 'US'), delegates: const >[ @@ -1827,9 +1830,9 @@ void main() { testWidgets('Material3 - BottomNavigationBar shows tool tips with text scaling on long press when labels are provided', (WidgetTester tester) async { const String label = 'Foo'; - Widget buildApp({ required double textScaleFactor }) { + Widget buildApp({ required TextScaler textScaler }) { return MediaQuery( - data: MediaQueryData(textScaleFactor: textScaleFactor), + data: MediaQueryData(textScaler: textScaler), child: Localizations( locale: const Locale('en', 'US'), delegates: const >[ @@ -1868,14 +1871,14 @@ void main() { ); } - await tester.pumpWidget(buildApp(textScaleFactor: 1.0)); + await tester.pumpWidget(buildApp(textScaler: TextScaler.noScaling)); expect(find.text(label), findsOneWidget); await tester.longPress(find.text(label)); expect(find.text(label), findsNWidgets(2)); expect(tester.getSize(find.text(label).last).height, equals(20.0)); await tester.pumpAndSettle(const Duration(seconds: 2)); - await tester.pumpWidget(buildApp(textScaleFactor: 4.0)); + await tester.pumpWidget(buildApp(textScaler: const TextScaler.linear(4.0))); expect(find.text(label), findsOneWidget); await tester.longPress(find.text(label)); expect(tester.getSize(find.text(label).last).height, equals(80.0)); diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart index 2f77a82ceb..96da8329a6 100644 --- a/packages/flutter/test/material/chip_test.dart +++ b/packages/flutter/test/material/chip_test.dart @@ -76,7 +76,7 @@ double getDeleteDrawerProgress(WidgetTester tester) => getRenderChip(tester)?.de Widget wrapForChip({ required Widget child, TextDirection textDirection = TextDirection.ltr, - double textScaleFactor = 1.0, + TextScaler textScaler = TextScaler.noScaling, ThemeData? theme, }) { return MaterialApp( @@ -84,7 +84,7 @@ Widget wrapForChip({ home: Directionality( textDirection: textDirection, child: MediaQuery( - data: MediaQueryData(textScaleFactor: textScaleFactor), + data: MediaQueryData(textScaler: textScaler), child: Material(child: child), ), ), @@ -836,7 +836,7 @@ void main() { await tester.pumpWidget( wrapForChip( - textScaleFactor: 3.0, + textScaler: const TextScaler.linear(3.0), child: const Column( children: [ Chip( @@ -906,7 +906,7 @@ void main() { await tester.pumpWidget( wrapForChip( - textScaleFactor: 3.0, + textScaler: const TextScaler.linear(3.0), child: const Column( children: [ Chip( diff --git a/packages/flutter/test/material/choice_chip_test.dart b/packages/flutter/test/material/choice_chip_test.dart index 6089dff706..248ad41576 100644 --- a/packages/flutter/test/material/choice_chip_test.dart +++ b/packages/flutter/test/material/choice_chip_test.dart @@ -46,7 +46,7 @@ DefaultTextStyle getLabelStyle(WidgetTester tester, String labelText) { Widget wrapForChip({ required Widget child, TextDirection textDirection = TextDirection.ltr, - double textScaleFactor = 1.0, + TextScaler textScaler = TextScaler.noScaling, Brightness brightness = Brightness.light, bool? useMaterial3, }) { @@ -55,7 +55,7 @@ Widget wrapForChip({ home: Directionality( textDirection: textDirection, child: MediaQuery( - data: MediaQueryData(textScaleFactor: textScaleFactor), + data: MediaQueryData(textScaler: textScaler), child: Material(child: child), ), ), diff --git a/packages/flutter/test/material/circle_avatar_test.dart b/packages/flutter/test/material/circle_avatar_test.dart index 7424b63f7c..72b297516c 100644 --- a/packages/flutter/test/material/circle_avatar_test.dart +++ b/packages/flutter/test/material/circle_avatar_test.dart @@ -171,7 +171,7 @@ void main() { expect(paragraph.text.style!.color, equals(theme.colorScheme.onPrimaryContainer)); }); - testWidgets('CircleAvatar text does not expand with textScaleFactor', (WidgetTester tester) async { + testWidgets('CircleAvatar text does not expand with textScaler', (WidgetTester tester) async { final Color foregroundColor = Colors.red.shade100; await tester.pumpWidget( wrap( @@ -188,7 +188,7 @@ void main() { wrap( child: MediaQuery( data: const MediaQueryData( - textScaleFactor: 2.0, + textScaler: TextScaler.linear(2.0), size: Size(111.0, 111.0), devicePixelRatio: 1.1, padding: EdgeInsets.all(11.0), @@ -204,7 +204,7 @@ void main() { expect(data.padding, equals(const EdgeInsets.all(11.0))); // This should be overridden to 1.0. - expect(data.textScaleFactor, equals(1.0)); + expect(data.textScaler, TextScaler.noScaling); return const Text('Z'); }, ), diff --git a/packages/flutter/test/material/dropdown_test.dart b/packages/flutter/test/material/dropdown_test.dart index 7240b8003a..0a41c99378 100644 --- a/packages/flutter/test/material/dropdown_test.dart +++ b/packages/flutter/test/material/dropdown_test.dart @@ -2269,16 +2269,16 @@ void main() { 'three', ]; String? item = items[0]; - late MediaQueryData mediaQuery; + late double textScale; await tester.pumpWidget( StatefulBuilder( builder: (BuildContext context, StateSetter setState) { return MaterialApp( builder: (BuildContext context, Widget? child) { - mediaQuery = MediaQuery.of(context); + textScale = MediaQuery.of(context).textScaler.scale(14) / 14; return MediaQuery( - data: mediaQuery, + data: MediaQueryData(textScaler: TextScaler.linear(textScale)), child: child!, ); }, @@ -2292,9 +2292,7 @@ void main() { onChanged: (String? newItem) { setState(() { item = newItem; - mediaQuery = mediaQuery.copyWith( - textScaleFactor: mediaQuery.textScaleFactor + 0.1, - ); + textScale += 0.1; }); }, ), diff --git a/packages/flutter/test/material/filter_chip_test.dart b/packages/flutter/test/material/filter_chip_test.dart index a48f7350fe..85605726e5 100644 --- a/packages/flutter/test/material/filter_chip_test.dart +++ b/packages/flutter/test/material/filter_chip_test.dart @@ -18,7 +18,7 @@ import 'feedback_tester.dart'; Widget wrapForChip({ required Widget child, TextDirection textDirection = TextDirection.ltr, - double textScaleFactor = 1.0, + TextScaler textScaler = TextScaler.noScaling, Brightness brightness = Brightness.light, bool? useMaterial3, }) { @@ -27,7 +27,7 @@ Widget wrapForChip({ home: Directionality( textDirection: textDirection, child: MediaQuery( - data: MediaQueryData(textScaleFactor: textScaleFactor), + data: MediaQueryData(textScaler: textScaler), child: Material(child: child), ), ), diff --git a/packages/flutter/test/material/input_chip_test.dart b/packages/flutter/test/material/input_chip_test.dart index 0d3504ff7a..715a586811 100644 --- a/packages/flutter/test/material/input_chip_test.dart +++ b/packages/flutter/test/material/input_chip_test.dart @@ -23,8 +23,9 @@ Widget wrapForChip({ theme: ThemeData(brightness: brightness, useMaterial3: useMaterial3), home: Directionality( textDirection: textDirection, - child: MediaQuery( - data: MediaQueryData(textScaleFactor: textScaleFactor), + child: MediaQuery.withClampedTextScaling( + minScaleFactor: textScaleFactor, + maxScaleFactor: textScaleFactor, child: Material(child: child), ), ), diff --git a/packages/flutter/test/material/list_tile_test.dart b/packages/flutter/test/material/list_tile_test.dart index b10cee6665..e0fbb7ba5c 100644 --- a/packages/flutter/test/material/list_tile_test.dart +++ b/packages/flutter/test/material/list_tile_test.dart @@ -59,22 +59,22 @@ void main() { const double leftPadding = 10.0; const double rightPadding = 20.0; - Widget buildFrame({ bool dense = false, bool isTwoLine = false, bool isThreeLine = false, double textScaleFactor = 1.0, double? subtitleScaleFactor }) { + Widget buildFrame({ bool dense = false, bool isTwoLine = false, bool isThreeLine = false, TextScaler textScaler = TextScaler.noScaling, TextScaler? subtitleScaler }) { hasSubtitle = isTwoLine || isThreeLine; - subtitleScaleFactor ??= textScaleFactor; + subtitleScaler ??= textScaler; return MaterialApp( theme: ThemeData(useMaterial3: true), home: MediaQuery( data: MediaQueryData( padding: const EdgeInsets.only(left: leftPadding, right: rightPadding), - textScaleFactor: textScaleFactor, + textScaler: textScaler, ), child: Material( child: Center( child: ListTile( leading: SizedBox(key: leadingKey, width: 24.0, height: 24.0), title: const Text('title'), - subtitle: hasSubtitle ? Text('subtitle', textScaleFactor: subtitleScaleFactor) : null, + subtitle: hasSubtitle ? Text('subtitle', textScaler: subtitleScaler) : null, trailing: SizedBox(key: trailingKey, width: 24.0, height: 24.0), dense: dense, isThreeLine: isThreeLine, @@ -146,12 +146,12 @@ void main() { testHorizontalGeometry(); testVerticalGeometry(88.0); - await tester.pumpWidget(buildFrame(textScaleFactor: 4.0)); + await tester.pumpWidget(buildFrame(textScaler: const TextScaler.linear(4.0))); testChildren(); testHorizontalGeometry(); testVerticalGeometry(112.0); - await tester.pumpWidget(buildFrame(isTwoLine: true, textScaleFactor: 4.0)); + await tester.pumpWidget(buildFrame(isTwoLine: true, textScaler: const TextScaler.linear(4.0))); testChildren(); testHorizontalGeometry(); if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 @@ -159,14 +159,14 @@ void main() { } // Make sure that the height of a large subtitle is taken into account. - await tester.pumpWidget(buildFrame(isTwoLine: true, textScaleFactor: 0.5, subtitleScaleFactor: 4.0)); + await tester.pumpWidget(buildFrame(isTwoLine: true, textScaler: const TextScaler.linear(0.5), subtitleScaler: const TextScaler.linear(4.0))); testChildren(); testHorizontalGeometry(); if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 testVerticalGeometry(108.0); } - await tester.pumpWidget(buildFrame(isThreeLine: true, textScaleFactor: 4.0)); + await tester.pumpWidget(buildFrame(isThreeLine: true, textScaler: const TextScaler.linear(4.0))); testChildren(); testHorizontalGeometry(); if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 @@ -2499,22 +2499,22 @@ void main() { const double leftPadding = 10.0; const double rightPadding = 20.0; - Widget buildFrame({ bool dense = false, bool isTwoLine = false, bool isThreeLine = false, double textScaleFactor = 1.0, double? subtitleScaleFactor }) { + Widget buildFrame({ bool dense = false, bool isTwoLine = false, bool isThreeLine = false, TextScaler textScaler = TextScaler.noScaling, TextScaler? subtitleScaler }) { hasSubtitle = isTwoLine || isThreeLine; - subtitleScaleFactor ??= textScaleFactor; + subtitleScaler ??= textScaler; return MaterialApp( theme: ThemeData(useMaterial3: false), home: MediaQuery( data: MediaQueryData( padding: const EdgeInsets.only(left: leftPadding, right: rightPadding), - textScaleFactor: textScaleFactor, + textScaler: textScaler, ), child: Material( child: Center( child: ListTile( leading: SizedBox(key: leadingKey, width: 24.0, height: 24.0), title: const Text('title'), - subtitle: hasSubtitle ? Text('subtitle', textScaleFactor: subtitleScaleFactor) : null, + subtitle: hasSubtitle ? Text('subtitle', textScaler: subtitleScaler) : null, trailing: SizedBox(key: trailingKey, width: 24.0, height: 24.0), dense: dense, isThreeLine: isThreeLine, @@ -2601,38 +2601,38 @@ void main() { testHorizontalGeometry(); testVerticalGeometry(76.0); - await tester.pumpWidget(buildFrame(textScaleFactor: 4.0)); + await tester.pumpWidget(buildFrame(textScaler: const TextScaler.linear(4.0))); testChildren(); testHorizontalGeometry(); testVerticalGeometry(72.0); - await tester.pumpWidget(buildFrame(dense: true, textScaleFactor: 4.0)); + await tester.pumpWidget(buildFrame(dense: true, textScaler: const TextScaler.linear(4.0))); testChildren(); testHorizontalGeometry(); testVerticalGeometry(72.0); - await tester.pumpWidget(buildFrame(isTwoLine: true, textScaleFactor: 4.0)); + await tester.pumpWidget(buildFrame(isTwoLine: true, textScaler: const TextScaler.linear(4.0))); testChildren(); testHorizontalGeometry(); testVerticalGeometry(128.0); // Make sure that the height of a large subtitle is taken into account. - await tester.pumpWidget(buildFrame(isTwoLine: true, textScaleFactor: 0.5, subtitleScaleFactor: 4.0)); + await tester.pumpWidget(buildFrame(isTwoLine: true, textScaler: const TextScaler.linear(0.5), subtitleScaler: const TextScaler.linear(4.0))); testChildren(); testHorizontalGeometry(); testVerticalGeometry(72.0); - await tester.pumpWidget(buildFrame(isTwoLine: true, dense: true, textScaleFactor: 4.0)); + await tester.pumpWidget(buildFrame(isTwoLine: true, dense: true, textScaler: const TextScaler.linear(4.0))); testChildren(); testHorizontalGeometry(); testVerticalGeometry(128.0); - await tester.pumpWidget(buildFrame(isThreeLine: true, textScaleFactor: 4.0)); + await tester.pumpWidget(buildFrame(isThreeLine: true, textScaler: const TextScaler.linear(4.0))); testChildren(); testHorizontalGeometry(); testVerticalGeometry(128.0); - await tester.pumpWidget(buildFrame(isThreeLine: true, dense: true, textScaleFactor: 4.0)); + await tester.pumpWidget(buildFrame(isThreeLine: true, dense: true, textScaler: const TextScaler.linear(4.0))); testChildren(); testHorizontalGeometry(); testVerticalGeometry(128.0); diff --git a/packages/flutter/test/material/navigation_bar_test.dart b/packages/flutter/test/material/navigation_bar_test.dart index 5e80d13eb4..4c38690afe 100644 --- a/packages/flutter/test/material/navigation_bar_test.dart +++ b/packages/flutter/test/material/navigation_bar_test.dart @@ -307,9 +307,9 @@ void main() { testWidgets('Material2 - NavigationBar shows tooltips with text scaling', (WidgetTester tester) async { const String label = 'A'; - Widget buildApp({ required double textScaleFactor }) { + Widget buildApp({ required TextScaler textScaler }) { return MediaQuery( - data: MediaQueryData(textScaleFactor: textScaleFactor), + data: MediaQueryData(textScaler: textScaler), child: Localizations( locale: const Locale('en', 'US'), delegates: const >[ @@ -346,7 +346,7 @@ void main() { ); } - await tester.pumpWidget(buildApp(textScaleFactor: 1.0)); + await tester.pumpWidget(buildApp(textScaler: TextScaler.noScaling)); expect(find.text(label), findsOneWidget); await tester.longPress(find.text(label)); expect(find.text(label), findsNWidgets(2)); @@ -357,7 +357,7 @@ void main() { // The duration is needed to ensure the tooltip disappears. await tester.pumpAndSettle(const Duration(seconds: 2)); - await tester.pumpWidget(buildApp(textScaleFactor: 4.0)); + await tester.pumpWidget(buildApp(textScaler: const TextScaler.linear(4.0))); expect(find.text(label), findsOneWidget); await tester.longPress(find.text(label)); expect(tester.getSize(find.text(label).last), Size(defaultTooltipSize.width * 4, defaultTooltipSize.height * 4)); @@ -366,9 +366,9 @@ void main() { testWidgets('Material3 - NavigationBar shows tooltips with text scaling', (WidgetTester tester) async { const String label = 'A'; - Widget buildApp({ required double textScaleFactor }) { + Widget buildApp({ required TextScaler textScaler }) { return MediaQuery( - data: MediaQueryData(textScaleFactor: textScaleFactor), + data: MediaQueryData(textScaler: textScaler), child: Localizations( locale: const Locale('en', 'US'), delegates: const >[ @@ -405,7 +405,7 @@ void main() { ); } - await tester.pumpWidget(buildApp(textScaleFactor: 1.0)); + await tester.pumpWidget(buildApp(textScaler: TextScaler.noScaling)); expect(find.text(label), findsOneWidget); await tester.longPress(find.text(label)); expect(find.text(label), findsNWidgets(2)); @@ -416,7 +416,7 @@ void main() { // The duration is needed to ensure the tooltip disappears. await tester.pumpAndSettle(const Duration(seconds: 2)); - await tester.pumpWidget(buildApp(textScaleFactor: 4.0)); + await tester.pumpWidget(buildApp(textScaler: const TextScaler.linear(4.0))); expect(find.text(label), findsOneWidget); await tester.longPress(find.text(label)); @@ -597,10 +597,10 @@ void main() { testWidgets('Navigation bar does not grow with text scale factor', (WidgetTester tester) async { const int animationMilliseconds = 800; - Widget widget({double textScaleFactor = 1}) { + Widget widget({ TextScaler textScaler = TextScaler.noScaling }) { return _buildWidget( MediaQuery( - data: MediaQueryData(textScaleFactor: textScaleFactor), + data: MediaQueryData(textScaler: textScaler), child: NavigationBar( animationDuration: const Duration(milliseconds: animationMilliseconds), destinations: const [ @@ -621,7 +621,7 @@ void main() { await tester.pumpWidget(widget()); final double initialHeight = tester.getSize(find.byType(NavigationBar)).height; - await tester.pumpWidget(widget(textScaleFactor: 2)); + await tester.pumpWidget(widget(textScaler: const TextScaler.linear(2))); final double newHeight = tester.getSize(find.byType(NavigationBar)).height; expect(newHeight, equals(initialHeight)); diff --git a/packages/flutter/test/material/outlined_button_test.dart b/packages/flutter/test/material/outlined_button_test.dart index a2f640e6cb..69832d3bfd 100644 --- a/packages/flutter/test/material/outlined_button_test.dart +++ b/packages/flutter/test/material/outlined_button_test.dart @@ -1088,8 +1088,9 @@ void main() { data: ThemeData(useMaterial3: false), child: Directionality( textDirection: TextDirection.ltr, - child: MediaQuery( - data: const MediaQueryData(textScaleFactor: 1.25), + child: MediaQuery.withClampedTextScaling( + minScaleFactor: 1.25, + maxScaleFactor: 1.25, child: Center( child: OutlinedButton( style: const ButtonStyle( @@ -1116,8 +1117,9 @@ void main() { data: ThemeData(useMaterial3: false), child: Directionality( textDirection: TextDirection.ltr, - child: MediaQuery( - data: const MediaQueryData(textScaleFactor: 3.0), + child: MediaQuery.withClampedTextScaling( + minScaleFactor: 3.0, + maxScaleFactor: 3.0, child: Center( child: OutlinedButton( onPressed: () {}, diff --git a/packages/flutter/test/material/paginated_data_table_test.dart b/packages/flutter/test/material/paginated_data_table_test.dart index 725ef14ae5..d0f67a246b 100644 --- a/packages/flutter/test/material/paginated_data_table_test.dart +++ b/packages/flutter/test/material/paginated_data_table_test.dart @@ -537,10 +537,9 @@ void main() { testWidgets('PaginatedDataTable with large text', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( - home: MediaQuery( - data: const MediaQueryData( - textScaleFactor: 20.0, - ), + home: MediaQuery.withClampedTextScaling( + minScaleFactor: 20.0, + maxScaleFactor: 20.0, child: PaginatedDataTable( header: const Text('HEADER'), source: source, diff --git a/packages/flutter/test/material/range_slider_test.dart b/packages/flutter/test/material/range_slider_test.dart index d00fe4275f..21ace26790 100644 --- a/packages/flutter/test/material/range_slider_test.dart +++ b/packages/flutter/test/material/range_slider_test.dart @@ -1657,7 +1657,7 @@ void main() { child: StatefulBuilder( builder: (BuildContext context, StateSetter setState) { return MediaQuery( - data: const MediaQueryData(textScaleFactor: 2.0), + data: const MediaQueryData(textScaler: TextScaler.linear(2)), child: Material( child: Center( child: Theme( diff --git a/packages/flutter/test/material/slider_test.dart b/packages/flutter/test/material/slider_test.dart index 5890aa02e1..f422c0449b 100644 --- a/packages/flutter/test/material/slider_test.dart +++ b/packages/flutter/test/material/slider_test.dart @@ -834,7 +834,7 @@ void main() { child: StatefulBuilder( builder: (BuildContext context, StateSetter setState) { return MediaQuery( - data: MediaQueryData(textScaleFactor: textScaleFactor), + data: MediaQueryData(textScaler: TextScaler.linear(textScaleFactor)), child: Material( child: Theme( data: Theme.of(context).copyWith( diff --git a/packages/flutter/test/material/slider_theme_test.dart b/packages/flutter/test/material/slider_theme_test.dart index 31d468a3ac..d389b98391 100644 --- a/packages/flutter/test/material/slider_theme_test.dart +++ b/packages/flutter/test/material/slider_theme_test.dart @@ -908,13 +908,13 @@ void main() { showValueIndicator: ShowValueIndicator.always, valueIndicatorShape: const PaddleSliderValueIndicatorShape(), ); - Widget buildApp(String value, { double sliderValue = 0.5, double textScale = 1.0 }) { + Widget buildApp(String value, { double sliderValue = 0.5, TextScaler textScaler = TextScaler.noScaling }) { return MaterialApp( theme: theme, home: Directionality( textDirection: TextDirection.ltr, child: MediaQuery( - data: MediaQueryData(textScaleFactor: textScale), + data: MediaQueryData(textScaler: textScaler), child: Material( child: Row( children: [ @@ -1025,7 +1025,7 @@ void main() { await gesture.up(); // Test that the neck stretches when the text scale gets smaller. - await tester.pumpWidget(buildApp('1000000', sliderValue: 0.0, textScale: 0.5)); + await tester.pumpWidget(buildApp('1000000', sliderValue: 0.0, textScaler: const TextScaler.linear(0.5))); center = tester.getCenter(find.byType(Slider)); gesture = await tester.startGesture(center); // Wait for value indicator animation to finish. @@ -1051,7 +1051,7 @@ void main() { await gesture.up(); // Test that the neck shrinks when the text scale gets larger. - await tester.pumpWidget(buildApp('1000000', sliderValue: 0.0, textScale: 2.5)); + await tester.pumpWidget(buildApp('1000000', sliderValue: 0.0, textScaler: const TextScaler.linear(2.5))); center = tester.getCenter(find.byType(Slider)); gesture = await tester.startGesture(center); // Wait for value indicator animation to finish. @@ -1092,13 +1092,13 @@ void main() { showValueIndicator: ShowValueIndicator.always, valueIndicatorShape: const PaddleSliderValueIndicatorShape(), ); - Widget buildApp(String value, { double sliderValue = 0.5, double textScale = 1.0 }) { + Widget buildApp(String value, { double sliderValue = 0.5, TextScaler textScaler = TextScaler.noScaling }) { return MaterialApp( theme: theme, home: Directionality( textDirection: TextDirection.ltr, child: MediaQuery( - data: MediaQueryData(textScaleFactor: textScale), + data: MediaQueryData(textScaler: textScaler), child: Material( child: Row( children: [ @@ -1209,7 +1209,7 @@ void main() { await gesture.up(); // Test that the neck stretches when the text scale gets smaller. - await tester.pumpWidget(buildApp('1000000', sliderValue: 0.0, textScale: 0.5)); + await tester.pumpWidget(buildApp('1000000', sliderValue: 0.0, textScaler: const TextScaler.linear(0.5))); center = tester.getCenter(find.byType(Slider)); gesture = await tester.startGesture(center); // Wait for value indicator animation to finish. @@ -1235,7 +1235,7 @@ void main() { await gesture.up(); // Test that the neck shrinks when the text scale gets larger. - await tester.pumpWidget(buildApp('1000000', sliderValue: 0.0, textScale: 2.5)); + await tester.pumpWidget(buildApp('1000000', sliderValue: 0.0, textScaler: const TextScaler.linear(2.5))); center = tester.getCenter(find.byType(Slider)); gesture = await tester.startGesture(center); // Wait for value indicator animation to finish. @@ -2040,13 +2040,13 @@ void main() { useMaterial3: true, platform: TargetPlatform.android, ); - Widget buildApp(String value, { double sliderValue = 0.5, double textScale = 1.0 }) { + Widget buildApp(String value, { double sliderValue = 0.5, TextScaler textScaler = TextScaler.noScaling }) { return MaterialApp( theme: theme, home: Directionality( textDirection: TextDirection.ltr, child: MediaQuery( - data: MediaQueryData(textScaleFactor: textScale), + data: MediaQueryData(textScaler: textScaler), child: Material( child: Row( children: [ @@ -2596,13 +2596,13 @@ void main() { useMaterial3: false, platform: TargetPlatform.android, ); - Widget buildApp(String value, { double sliderValue = 0.5, double textScale = 1.0 }) { + Widget buildApp(String value, { double sliderValue = 0.5, TextScaler textScaler = TextScaler.noScaling }) { return MaterialApp( theme: theme, home: Directionality( textDirection: TextDirection.ltr, child: MediaQuery( - data: MediaQueryData(textScaleFactor: textScale), + data: MediaQueryData(textScaler: textScaler), child: Material( child: Row( children: [ diff --git a/packages/flutter/test/material/text_button_test.dart b/packages/flutter/test/material/text_button_test.dart index d7cf47c8a8..809c1c52cb 100644 --- a/packages/flutter/test/material/text_button_test.dart +++ b/packages/flutter/test/material/text_button_test.dart @@ -615,8 +615,9 @@ void main() { data: ThemeData(useMaterial3: false), child: Directionality( textDirection: TextDirection.ltr, - child: MediaQuery( - data: const MediaQueryData(textScaleFactor: 1.25), + child: MediaQuery.withClampedTextScaling( + minScaleFactor: 1.25, + maxScaleFactor: 1.25, child: Center( child: TextButton( onPressed: () { }, @@ -639,8 +640,9 @@ void main() { data: ThemeData(useMaterial3: false), child: Directionality( textDirection: TextDirection.ltr, - child: MediaQuery( - data: const MediaQueryData(textScaleFactor: 3.0), + child: MediaQuery.withClampedTextScaling( + minScaleFactor: 3.0, + maxScaleFactor: 3.0, child: Center( child: TextButton( onPressed: () { }, diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index 79323b47b2..8d305794a4 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -8854,7 +8854,7 @@ void main() { theme: ThemeData(useMaterial3: false), home: Scaffold( body: MediaQuery( - data: const MediaQueryData(textScaleFactor: 4.0), + data: const MediaQueryData(textScaler: TextScaler.linear(4.0)), child: Center( child: TextField( decoration: const InputDecoration(labelText: 'Label', border: UnderlineInputBorder()), diff --git a/packages/flutter/test/material/time_picker_test.dart b/packages/flutter/test/material/time_picker_test.dart index 013a94e65d..32e85d8651 100644 --- a/packages/flutter/test/material/time_picker_test.dart +++ b/packages/flutter/test/material/time_picker_test.dart @@ -1083,7 +1083,7 @@ void main() { // Verify that the time display is not affected by text scale. await mediaQueryBoilerplate( tester, - textScaleFactor: 2, + textScaler: const TextScaler.linear(2), initialTime: const TimeOfDay(hour: 7, minute: 41), materialType: materialType, ); @@ -1098,7 +1098,7 @@ void main() { // Verify that text scale for AM/PM is at most 2x. await mediaQueryBoilerplate( tester, - textScaleFactor: 3, + textScaler: const TextScaler.linear(3), initialTime: const TimeOfDay(hour: 7, minute: 41), materialType: materialType, ); @@ -1996,7 +1996,7 @@ Future mediaQueryBoilerplate( WidgetTester tester, { bool alwaysUse24HourFormat = false, TimeOfDay initialTime = const TimeOfDay(hour: 7, minute: 0), - double textScaleFactor = 1, + TextScaler textScaler = TextScaler.noScaling, TimePickerEntryMode entryMode = TimePickerEntryMode.dial, String? helpText, String? hourLabelText, @@ -2020,7 +2020,7 @@ Future mediaQueryBoilerplate( child: MediaQuery( data: MediaQueryData( alwaysUse24HourFormat: alwaysUse24HourFormat, - textScaleFactor: textScaleFactor, + textScaler: textScaler, accessibleNavigation: accessibleNavigation, size: tester.view.physicalSize / tester.view.devicePixelRatio, ), diff --git a/packages/flutter/test/material/tooltip_test.dart b/packages/flutter/test/material/tooltip_test.dart index 76e5fc7524..205dbad447 100644 --- a/packages/flutter/test/material/tooltip_test.dart +++ b/packages/flutter/test/material/tooltip_test.dart @@ -1930,12 +1930,12 @@ void main() { semantics.dispose(); }); - testWidgets('Material2 - Tooltip text scales with textScaleFactor', (WidgetTester tester) async { - Widget buildApp(String text, { required double textScaleFactor }) { + testWidgets('Material2 - Tooltip text scales with textScaler', (WidgetTester tester) async { + Widget buildApp(String text, { required TextScaler textScaler }) { return MaterialApp( theme: ThemeData(useMaterial3: false), home: MediaQuery( - data: MediaQueryData(textScaleFactor: textScaleFactor), + data: MediaQueryData(textScaler: textScaler), child: Directionality( textDirection: TextDirection.ltr, child: Navigator( @@ -1961,7 +1961,7 @@ void main() { ); } - await tester.pumpWidget(buildApp(tooltipText, textScaleFactor: 1.0)); + await tester.pumpWidget(buildApp(tooltipText, textScaler: TextScaler.noScaling)); await tester.longPress(find.byType(Tooltip)); expect(find.text(tooltipText), findsOneWidget); expect(tester.getSize(find.text(tooltipText)), equals(const Size(42.0, 14.0))); @@ -1970,7 +1970,7 @@ void main() { ); expect(tip.size.height, equals(32.0)); - await tester.pumpWidget(buildApp(tooltipText, textScaleFactor: 4.0)); + await tester.pumpWidget(buildApp(tooltipText, textScaler: const TextScaler.linear(4.0))); await tester.longPress(find.byType(Tooltip)); expect(find.text(tooltipText), findsOneWidget); expect(tester.getSize(find.text(tooltipText)), equals(const Size(168.0, 56.0))); @@ -1981,10 +1981,10 @@ void main() { }); testWidgets('Material3 - Tooltip text scales with textScaleFactor', (WidgetTester tester) async { - Widget buildApp(String text, { required double textScaleFactor }) { + Widget buildApp(String text, { required TextScaler textScaler }) { return MaterialApp( home: MediaQuery( - data: MediaQueryData(textScaleFactor: textScaleFactor), + data: MediaQueryData(textScaler: textScaler), child: Navigator( onGenerateRoute: (RouteSettings settings) { return MaterialPageRoute( @@ -2007,7 +2007,7 @@ void main() { ); } - await tester.pumpWidget(buildApp(tooltipText, textScaleFactor: 1.0)); + await tester.pumpWidget(buildApp(tooltipText, textScaler: TextScaler.noScaling)); await tester.longPress(find.byType(Tooltip)); expect(find.text(tooltipText), findsOneWidget); expect(tester.getSize(find.text(tooltipText)).width, equals(42.75)); @@ -2017,7 +2017,7 @@ void main() { ); expect(tip.size.height, equals(32.0)); - await tester.pumpWidget(buildApp(tooltipText, textScaleFactor: 4.0)); + await tester.pumpWidget(buildApp(tooltipText, textScaler: const TextScaler.linear(4.0))); await tester.longPress(find.byType(Tooltip)); expect(find.text(tooltipText), findsOneWidget); expect(tester.getSize(find.text(tooltipText)).width, equals(168.75)); diff --git a/packages/flutter/test/material/value_indicating_slider_test.dart b/packages/flutter/test/material/value_indicating_slider_test.dart index 8db17de257..6562f9ecac 100644 --- a/packages/flutter/test/material/value_indicating_slider_test.dart +++ b/packages/flutter/test/material/value_indicating_slider_test.dart @@ -410,8 +410,9 @@ Future _buildValueIndicatorStaticSlider( body: Builder( builder: (BuildContext context) { return Center( - child: MediaQuery( - data: MediaQueryData(textScaleFactor: textScale), + child: MediaQuery.withClampedTextScaling( + minScaleFactor: textScale, + maxScaleFactor: textScale, child: SliderTheme( data: Theme.of(context).sliderTheme.copyWith( showValueIndicator: ShowValueIndicator.always, diff --git a/packages/flutter/test/widgets/app_test.dart b/packages/flutter/test/widgets/app_test.dart index 4393781814..0d8f08cf82 100644 --- a/packages/flutter/test/widgets/app_test.dart +++ b/packages/flutter/test/widgets/app_test.dart @@ -624,13 +624,13 @@ void main() { ); await tester.pumpWidget( - MediaQuery(data: const MediaQueryData(textScaleFactor: 10), child: widget), + MediaQuery(data: const MediaQueryData(textScaler: TextScaler.linear(10)), child: widget), ); expect(routeBuildCount, equals(1)); await tester.pumpWidget( - MediaQuery(data: const MediaQueryData(textScaleFactor: 20), child: widget), + MediaQuery(data: const MediaQueryData(textScaler: TextScaler.linear(20)), child: widget), ); expect(routeBuildCount, equals(1)); diff --git a/packages/flutter/test/widgets/media_query_test.dart b/packages/flutter/test/widgets/media_query_test.dart index e337c8f1d7..1c6315378f 100644 --- a/packages/flutter/test/widgets/media_query_test.dart +++ b/packages/flutter/test/widgets/media_query_test.dart @@ -164,7 +164,7 @@ void main() { testWidgets('MediaQueryData.fromView uses platformData if provided', (WidgetTester tester) async { const MediaQueryData platformData = MediaQueryData( - textScaleFactor: 1234, + textScaler: TextScaler.linear(1234), platformBrightness: Brightness.dark, accessibleNavigation: true, invertColors: true, @@ -231,7 +231,7 @@ void main() { testWidgets('MediaQuery.fromView injects a new MediaQuery with data from view, preserving platform-specific data', (WidgetTester tester) async { const MediaQueryData platformData = MediaQueryData( - textScaleFactor: 1234, + textScaler: TextScaler.linear(1234), platformBrightness: Brightness.dark, accessibleNavigation: true, invertColors: true, diff --git a/packages/flutter/test/widgets/text_test.dart b/packages/flutter/test/widgets/text_test.dart index bd891575b5..ab90c57032 100644 --- a/packages/flutter/test/widgets/text_test.dart +++ b/packages/flutter/test/widgets/text_test.dart @@ -14,9 +14,10 @@ import 'semantics_tester.dart'; void main() { testWidgets('Text respects media query', (WidgetTester tester) async { - await tester.pumpWidget(const MediaQuery( - data: MediaQueryData(textScaleFactor: 1.3), - child: Center( + await tester.pumpWidget(MediaQuery.withClampedTextScaling( + minScaleFactor: 1.3, + maxScaleFactor: 1.3, + child: const Center( child: Text('Hello', textDirection: TextDirection.ltr), ), ));