Skip to content

Commit 07c1ef2

Browse files
authored
Utility methods for measuring text (#111493)
1 parent 7b5241b commit 07c1ef2

File tree

3 files changed

+105
-11
lines changed

3 files changed

+105
-11
lines changed

packages/flutter/lib/src/cupertino/date_picker.dart

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -470,23 +470,13 @@ class CupertinoDatePicker extends StatefulWidget {
470470

471471
assert(longestText != '', 'column type is not appropriate');
472472

473-
final TextPainter painter = TextPainter(
473+
return TextPainter.computeMaxIntrinsicWidth(
474474
text: TextSpan(
475475
style: _themeTextStyle(context),
476476
text: longestText,
477477
),
478478
textDirection: Directionality.of(context),
479479
);
480-
481-
// This operation is expensive and should be avoided. It is called here only
482-
// because there's no other way to get the information we want without
483-
// laying out the text.
484-
painter.layout();
485-
try {
486-
return painter.maxIntrinsicWidth;
487-
} finally {
488-
painter.dispose();
489-
}
490480
}
491481
}
492482

packages/flutter/lib/src/painting/text_painter.dart

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,86 @@ class TextPainter {
217217
_textWidthBasis = textWidthBasis,
218218
_textHeightBehavior = textHeightBehavior;
219219

220+
/// Computes the width of a configured [TextPainter].
221+
///
222+
/// This is a convenience method that creates a text painter with the supplied
223+
/// parameters, lays it out with the supplied [minWidth] and [maxWidth], and
224+
/// returns its [TextPainter.width] making sure to dispose the underlying
225+
/// resources.
226+
static double computeWidth({
227+
required InlineSpan text,
228+
TextAlign textAlign = TextAlign.start,
229+
TextDirection? textDirection,
230+
double textScaleFactor = 1.0,
231+
int? maxLines,
232+
String? ellipsis,
233+
Locale? locale,
234+
StrutStyle? strutStyle,
235+
TextWidthBasis textWidthBasis = TextWidthBasis.parent,
236+
ui.TextHeightBehavior? textHeightBehavior,
237+
double minWidth = 0.0,
238+
double maxWidth = double.infinity,
239+
}) {
240+
final TextPainter painter = TextPainter(
241+
text: text,
242+
textAlign: textAlign,
243+
textDirection: textDirection,
244+
textScaleFactor: textScaleFactor,
245+
maxLines: maxLines,
246+
ellipsis: ellipsis,
247+
locale: locale,
248+
strutStyle: strutStyle,
249+
textWidthBasis: textWidthBasis,
250+
textHeightBehavior: textHeightBehavior,
251+
)..layout(minWidth: minWidth, maxWidth: maxWidth);
252+
253+
try {
254+
return painter.width;
255+
} finally {
256+
painter.dispose();
257+
}
258+
}
259+
260+
/// Computes the max intrinsic width of a configured [TextPainter].
261+
///
262+
/// This is a convenience method that creates a text painter with the supplied
263+
/// parameters, lays it out with the supplied [minWidth] and [maxWidth], and
264+
/// returns its [TextPainter.maxIntrinsicWidth] making sure to dispose the
265+
/// underlying resources.
266+
static double computeMaxIntrinsicWidth({
267+
required InlineSpan text,
268+
TextAlign textAlign = TextAlign.start,
269+
TextDirection? textDirection,
270+
double textScaleFactor = 1.0,
271+
int? maxLines,
272+
String? ellipsis,
273+
Locale? locale,
274+
StrutStyle? strutStyle,
275+
TextWidthBasis textWidthBasis = TextWidthBasis.parent,
276+
ui.TextHeightBehavior? textHeightBehavior,
277+
double minWidth = 0.0,
278+
double maxWidth = double.infinity,
279+
}) {
280+
final TextPainter painter = TextPainter(
281+
text: text,
282+
textAlign: textAlign,
283+
textDirection: textDirection,
284+
textScaleFactor: textScaleFactor,
285+
maxLines: maxLines,
286+
ellipsis: ellipsis,
287+
locale: locale,
288+
strutStyle: strutStyle,
289+
textWidthBasis: textWidthBasis,
290+
textHeightBehavior: textHeightBehavior,
291+
)..layout(minWidth: minWidth, maxWidth: maxWidth);
292+
293+
try {
294+
return painter.maxIntrinsicWidth;
295+
} finally {
296+
painter.dispose();
297+
}
298+
}
299+
220300
// _paragraph being null means the text needs layout because of style changes.
221301
// Setting _paragraph to null invalidates all the layout cache.
222302
//

packages/flutter/test/painting/text_painter_test.dart

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,30 @@ void main() {
11841184
painter.dispose();
11851185
expect(painter.debugDisposed, true);
11861186
});
1187+
1188+
test('TextPainter computeWidth', () {
1189+
const InlineSpan text = TextSpan(text: 'foobar');
1190+
final TextPainter painter = TextPainter(text: text, textDirection: TextDirection.ltr);
1191+
painter.layout();
1192+
expect(painter.width, TextPainter.computeWidth(text: text, textDirection: TextDirection.ltr));
1193+
1194+
painter.layout(minWidth: 500);
1195+
expect(painter.width, TextPainter.computeWidth(text: text, textDirection: TextDirection.ltr, minWidth: 500));
1196+
1197+
painter.dispose();
1198+
});
1199+
1200+
test('TextPainter computeMaxIntrinsicWidth', () {
1201+
const InlineSpan text = TextSpan(text: 'foobar');
1202+
final TextPainter painter = TextPainter(text: text, textDirection: TextDirection.ltr);
1203+
painter.layout();
1204+
expect(painter.maxIntrinsicWidth, TextPainter.computeMaxIntrinsicWidth(text: text, textDirection: TextDirection.ltr));
1205+
1206+
painter.layout(minWidth: 500);
1207+
expect(painter.maxIntrinsicWidth, TextPainter.computeMaxIntrinsicWidth(text: text, textDirection: TextDirection.ltr, minWidth: 500));
1208+
1209+
painter.dispose();
1210+
});
11871211
}
11881212

11891213
class MockCanvas extends Fake implements Canvas {

0 commit comments

Comments
 (0)