diff --git a/packages/flutter/lib/src/cupertino/date_picker.dart b/packages/flutter/lib/src/cupertino/date_picker.dart index 19b0a256f72..579ca40105b 100644 --- a/packages/flutter/lib/src/cupertino/date_picker.dart +++ b/packages/flutter/lib/src/cupertino/date_picker.dart @@ -470,23 +470,13 @@ class CupertinoDatePicker extends StatefulWidget { assert(longestText != '', 'column type is not appropriate'); - final TextPainter painter = TextPainter( + return TextPainter.computeMaxIntrinsicWidth( text: TextSpan( style: _themeTextStyle(context), text: longestText, ), textDirection: Directionality.of(context), ); - - // This operation is expensive and should be avoided. It is called here only - // because there's no other way to get the information we want without - // laying out the text. - painter.layout(); - try { - return painter.maxIntrinsicWidth; - } finally { - painter.dispose(); - } } } diff --git a/packages/flutter/lib/src/painting/text_painter.dart b/packages/flutter/lib/src/painting/text_painter.dart index 9a0fb8b3d98..81c45e34c5c 100644 --- a/packages/flutter/lib/src/painting/text_painter.dart +++ b/packages/flutter/lib/src/painting/text_painter.dart @@ -217,6 +217,86 @@ class TextPainter { _textWidthBasis = textWidthBasis, _textHeightBehavior = textHeightBehavior; + /// Computes the width of a configured [TextPainter]. + /// + /// This is a convenience method that creates a text painter with the supplied + /// parameters, lays it out with the supplied [minWidth] and [maxWidth], and + /// returns its [TextPainter.width] making sure to dispose the underlying + /// resources. + static double computeWidth({ + required InlineSpan text, + TextAlign textAlign = TextAlign.start, + TextDirection? textDirection, + double textScaleFactor = 1.0, + int? maxLines, + String? ellipsis, + Locale? locale, + StrutStyle? strutStyle, + TextWidthBasis textWidthBasis = TextWidthBasis.parent, + ui.TextHeightBehavior? textHeightBehavior, + double minWidth = 0.0, + double maxWidth = double.infinity, + }) { + final TextPainter painter = TextPainter( + text: text, + textAlign: textAlign, + textDirection: textDirection, + textScaleFactor: textScaleFactor, + maxLines: maxLines, + ellipsis: ellipsis, + locale: locale, + strutStyle: strutStyle, + textWidthBasis: textWidthBasis, + textHeightBehavior: textHeightBehavior, + )..layout(minWidth: minWidth, maxWidth: maxWidth); + + try { + return painter.width; + } finally { + painter.dispose(); + } + } + + /// Computes the max intrinsic width of a configured [TextPainter]. + /// + /// This is a convenience method that creates a text painter with the supplied + /// parameters, lays it out with the supplied [minWidth] and [maxWidth], and + /// returns its [TextPainter.maxIntrinsicWidth] making sure to dispose the + /// underlying resources. + static double computeMaxIntrinsicWidth({ + required InlineSpan text, + TextAlign textAlign = TextAlign.start, + TextDirection? textDirection, + double textScaleFactor = 1.0, + int? maxLines, + String? ellipsis, + Locale? locale, + StrutStyle? strutStyle, + TextWidthBasis textWidthBasis = TextWidthBasis.parent, + ui.TextHeightBehavior? textHeightBehavior, + double minWidth = 0.0, + double maxWidth = double.infinity, + }) { + final TextPainter painter = TextPainter( + text: text, + textAlign: textAlign, + textDirection: textDirection, + textScaleFactor: textScaleFactor, + maxLines: maxLines, + ellipsis: ellipsis, + locale: locale, + strutStyle: strutStyle, + textWidthBasis: textWidthBasis, + textHeightBehavior: textHeightBehavior, + )..layout(minWidth: minWidth, maxWidth: maxWidth); + + try { + return painter.maxIntrinsicWidth; + } finally { + painter.dispose(); + } + } + // _paragraph being null means the text needs layout because of style changes. // Setting _paragraph to null invalidates all the layout cache. // diff --git a/packages/flutter/test/painting/text_painter_test.dart b/packages/flutter/test/painting/text_painter_test.dart index 7d8a75a71a0..4c76745e6ec 100644 --- a/packages/flutter/test/painting/text_painter_test.dart +++ b/packages/flutter/test/painting/text_painter_test.dart @@ -1184,6 +1184,30 @@ void main() { painter.dispose(); expect(painter.debugDisposed, true); }); + + test('TextPainter computeWidth', () { + const InlineSpan text = TextSpan(text: 'foobar'); + final TextPainter painter = TextPainter(text: text, textDirection: TextDirection.ltr); + painter.layout(); + expect(painter.width, TextPainter.computeWidth(text: text, textDirection: TextDirection.ltr)); + + painter.layout(minWidth: 500); + expect(painter.width, TextPainter.computeWidth(text: text, textDirection: TextDirection.ltr, minWidth: 500)); + + painter.dispose(); + }); + + test('TextPainter computeMaxIntrinsicWidth', () { + const InlineSpan text = TextSpan(text: 'foobar'); + final TextPainter painter = TextPainter(text: text, textDirection: TextDirection.ltr); + painter.layout(); + expect(painter.maxIntrinsicWidth, TextPainter.computeMaxIntrinsicWidth(text: text, textDirection: TextDirection.ltr)); + + painter.layout(minWidth: 500); + expect(painter.maxIntrinsicWidth, TextPainter.computeMaxIntrinsicWidth(text: text, textDirection: TextDirection.ltr, minWidth: 500)); + + painter.dispose(); + }); } class MockCanvas extends Fake implements Canvas {