Add TextOverflow into TextStyle (#78927)
This commit is contained in:
parent
dba71259d5
commit
65388ee2ee
@ -21,6 +21,24 @@ export 'package:flutter/services.dart' show TextRange, TextSelection;
|
|||||||
// defaults set in the engine (eg, LibTxt's text_style.h, paragraph_style.h).
|
// defaults set in the engine (eg, LibTxt's text_style.h, paragraph_style.h).
|
||||||
const double _kDefaultFontSize = 14.0;
|
const double _kDefaultFontSize = 14.0;
|
||||||
|
|
||||||
|
/// How overflowing text should be handled.
|
||||||
|
///
|
||||||
|
/// A [TextOverflow] can be passed to [Text] and [RichText] via their
|
||||||
|
/// [Text.overflow] and [RichText.overflow] properties respectively.
|
||||||
|
enum TextOverflow {
|
||||||
|
/// Clip the overflowing text to fix its container.
|
||||||
|
clip,
|
||||||
|
|
||||||
|
/// Fade the overflowing text to transparent.
|
||||||
|
fade,
|
||||||
|
|
||||||
|
/// Use an ellipsis to indicate that the text has overflowed.
|
||||||
|
ellipsis,
|
||||||
|
|
||||||
|
/// Render overflowing text outside of its container.
|
||||||
|
visible,
|
||||||
|
}
|
||||||
|
|
||||||
/// Holds the [Size] and baseline required to represent the dimensions of
|
/// Holds the [Size] and baseline required to represent the dimensions of
|
||||||
/// a placeholder in text.
|
/// a placeholder in text.
|
||||||
///
|
///
|
||||||
|
@ -10,6 +10,7 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'basic_types.dart';
|
import 'basic_types.dart';
|
||||||
import 'colors.dart';
|
import 'colors.dart';
|
||||||
import 'strut_style.dart';
|
import 'strut_style.dart';
|
||||||
|
import 'text_painter.dart';
|
||||||
|
|
||||||
const String _kDefaultDebugLabel = 'unknown';
|
const String _kDefaultDebugLabel = 'unknown';
|
||||||
|
|
||||||
@ -480,6 +481,7 @@ class TextStyle with Diagnosticable {
|
|||||||
String? fontFamily,
|
String? fontFamily,
|
||||||
List<String>? fontFamilyFallback,
|
List<String>? fontFamilyFallback,
|
||||||
String? package,
|
String? package,
|
||||||
|
this.overflow,
|
||||||
}) : fontFamily = package == null ? fontFamily : 'packages/$package/$fontFamily',
|
}) : fontFamily = package == null ? fontFamily : 'packages/$package/$fontFamily',
|
||||||
_fontFamilyFallback = fontFamilyFallback,
|
_fontFamilyFallback = fontFamilyFallback,
|
||||||
_package = package,
|
_package = package,
|
||||||
@ -758,6 +760,9 @@ class TextStyle with Diagnosticable {
|
|||||||
/// these variants will be used for rendering.
|
/// these variants will be used for rendering.
|
||||||
final List<ui.FontFeature>? fontFeatures;
|
final List<ui.FontFeature>? fontFeatures;
|
||||||
|
|
||||||
|
/// How visual text overflow should be handled.
|
||||||
|
final TextOverflow? overflow;
|
||||||
|
|
||||||
/// Creates a copy of this text style but with the given fields replaced with
|
/// Creates a copy of this text style but with the given fields replaced with
|
||||||
/// the new values.
|
/// the new values.
|
||||||
///
|
///
|
||||||
@ -791,6 +796,7 @@ class TextStyle with Diagnosticable {
|
|||||||
TextDecorationStyle? decorationStyle,
|
TextDecorationStyle? decorationStyle,
|
||||||
double? decorationThickness,
|
double? decorationThickness,
|
||||||
String? debugLabel,
|
String? debugLabel,
|
||||||
|
TextOverflow? overflow,
|
||||||
}) {
|
}) {
|
||||||
assert(color == null || foreground == null, _kColorForegroundWarning);
|
assert(color == null || foreground == null, _kColorForegroundWarning);
|
||||||
assert(backgroundColor == null || background == null, _kColorBackgroundWarning);
|
assert(backgroundColor == null || background == null, _kColorBackgroundWarning);
|
||||||
@ -824,6 +830,7 @@ class TextStyle with Diagnosticable {
|
|||||||
decorationStyle: decorationStyle ?? this.decorationStyle,
|
decorationStyle: decorationStyle ?? this.decorationStyle,
|
||||||
decorationThickness: decorationThickness ?? this.decorationThickness,
|
decorationThickness: decorationThickness ?? this.decorationThickness,
|
||||||
debugLabel: newDebugLabel,
|
debugLabel: newDebugLabel,
|
||||||
|
overflow: overflow ?? this.overflow
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -881,6 +888,7 @@ class TextStyle with Diagnosticable {
|
|||||||
Locale? locale,
|
Locale? locale,
|
||||||
List<ui.Shadow>? shadows,
|
List<ui.Shadow>? shadows,
|
||||||
List<ui.FontFeature>? fontFeatures,
|
List<ui.FontFeature>? fontFeatures,
|
||||||
|
TextOverflow? overflow,
|
||||||
}) {
|
}) {
|
||||||
assert(fontSizeFactor != null);
|
assert(fontSizeFactor != null);
|
||||||
assert(fontSizeDelta != null);
|
assert(fontSizeDelta != null);
|
||||||
@ -929,6 +937,7 @@ class TextStyle with Diagnosticable {
|
|||||||
decorationColor: decorationColor ?? this.decorationColor,
|
decorationColor: decorationColor ?? this.decorationColor,
|
||||||
decorationStyle: decorationStyle ?? this.decorationStyle,
|
decorationStyle: decorationStyle ?? this.decorationStyle,
|
||||||
decorationThickness: decorationThickness == null ? null : decorationThickness! * decorationThicknessFactor + decorationThicknessDelta,
|
decorationThickness: decorationThickness == null ? null : decorationThickness! * decorationThicknessFactor + decorationThicknessDelta,
|
||||||
|
overflow: overflow ?? this.overflow,
|
||||||
debugLabel: modifiedDebugLabel,
|
debugLabel: modifiedDebugLabel,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -989,6 +998,7 @@ class TextStyle with Diagnosticable {
|
|||||||
decorationColor: other.decorationColor,
|
decorationColor: other.decorationColor,
|
||||||
decorationStyle: other.decorationStyle,
|
decorationStyle: other.decorationStyle,
|
||||||
decorationThickness: other.decorationThickness,
|
decorationThickness: other.decorationThickness,
|
||||||
|
overflow: other.overflow,
|
||||||
debugLabel: mergedDebugLabel,
|
debugLabel: mergedDebugLabel,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1043,6 +1053,7 @@ class TextStyle with Diagnosticable {
|
|||||||
decorationColor: Color.lerp(null, b.decorationColor, t),
|
decorationColor: Color.lerp(null, b.decorationColor, t),
|
||||||
decorationStyle: t < 0.5 ? null : b.decorationStyle,
|
decorationStyle: t < 0.5 ? null : b.decorationStyle,
|
||||||
decorationThickness: t < 0.5 ? null : b.decorationThickness,
|
decorationThickness: t < 0.5 ? null : b.decorationThickness,
|
||||||
|
overflow: t < 0.5 ? null : b.overflow,
|
||||||
debugLabel: lerpDebugLabel,
|
debugLabel: lerpDebugLabel,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1071,6 +1082,7 @@ class TextStyle with Diagnosticable {
|
|||||||
decorationColor: Color.lerp(a.decorationColor, null, t),
|
decorationColor: Color.lerp(a.decorationColor, null, t),
|
||||||
decorationStyle: t < 0.5 ? a.decorationStyle : null,
|
decorationStyle: t < 0.5 ? a.decorationStyle : null,
|
||||||
decorationThickness: t < 0.5 ? a.decorationThickness : null,
|
decorationThickness: t < 0.5 ? a.decorationThickness : null,
|
||||||
|
overflow: t < 0.5 ? a.overflow : null,
|
||||||
debugLabel: lerpDebugLabel,
|
debugLabel: lerpDebugLabel,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1106,6 +1118,7 @@ class TextStyle with Diagnosticable {
|
|||||||
decorationColor: Color.lerp(a.decorationColor, b.decorationColor, t),
|
decorationColor: Color.lerp(a.decorationColor, b.decorationColor, t),
|
||||||
decorationStyle: t < 0.5 ? a.decorationStyle : b.decorationStyle,
|
decorationStyle: t < 0.5 ? a.decorationStyle : b.decorationStyle,
|
||||||
decorationThickness: ui.lerpDouble(a.decorationThickness ?? b.decorationThickness, b.decorationThickness ?? a.decorationThickness, t),
|
decorationThickness: ui.lerpDouble(a.decorationThickness ?? b.decorationThickness, b.decorationThickness ?? a.decorationThickness, t),
|
||||||
|
overflow: t < 0.5 ? a.overflow : b.overflow,
|
||||||
debugLabel: lerpDebugLabel,
|
debugLabel: lerpDebugLabel,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1218,7 +1231,8 @@ class TextStyle with Diagnosticable {
|
|||||||
background != other.background ||
|
background != other.background ||
|
||||||
!listEquals(shadows, other.shadows) ||
|
!listEquals(shadows, other.shadows) ||
|
||||||
!listEquals(fontFeatures, other.fontFeatures) ||
|
!listEquals(fontFeatures, other.fontFeatures) ||
|
||||||
!listEquals(fontFamilyFallback, other.fontFamilyFallback))
|
!listEquals(fontFamilyFallback, other.fontFamilyFallback) ||
|
||||||
|
overflow != other.overflow)
|
||||||
return RenderComparison.layout;
|
return RenderComparison.layout;
|
||||||
if (color != other.color ||
|
if (color != other.color ||
|
||||||
backgroundColor != other.backgroundColor ||
|
backgroundColor != other.backgroundColor ||
|
||||||
@ -1258,7 +1272,8 @@ class TextStyle with Diagnosticable {
|
|||||||
&& other.decorationThickness == decorationThickness
|
&& other.decorationThickness == decorationThickness
|
||||||
&& listEquals(other.shadows, shadows)
|
&& listEquals(other.shadows, shadows)
|
||||||
&& listEquals(other.fontFeatures, fontFeatures)
|
&& listEquals(other.fontFeatures, fontFeatures)
|
||||||
&& listEquals(other.fontFamilyFallback, fontFamilyFallback);
|
&& listEquals(other.fontFamilyFallback, fontFamilyFallback)
|
||||||
|
&& other.overflow == overflow;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -1285,6 +1300,7 @@ class TextStyle with Diagnosticable {
|
|||||||
hashList(shadows),
|
hashList(shadows),
|
||||||
hashList(fontFeatures),
|
hashList(fontFeatures),
|
||||||
hashList(fontFamilyFallback),
|
hashList(fontFamilyFallback),
|
||||||
|
overflow,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1355,5 +1371,7 @@ class TextStyle with Diagnosticable {
|
|||||||
|
|
||||||
if (!styleSpecified)
|
if (!styleSpecified)
|
||||||
properties.add(FlagProperty('inherit', value: inherit, ifTrue: '$prefix<all styles inherited>', ifFalse: '$prefix<no style specified>'));
|
properties.add(FlagProperty('inherit', value: inherit, ifTrue: '$prefix<all styles inherited>', ifFalse: '$prefix<no style specified>'));
|
||||||
|
|
||||||
|
styles.add(EnumProperty<TextOverflow>('${prefix}overflow', overflow, defaultValue: null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,24 +16,6 @@ import 'box.dart';
|
|||||||
import 'debug.dart';
|
import 'debug.dart';
|
||||||
import 'object.dart';
|
import 'object.dart';
|
||||||
|
|
||||||
/// How overflowing text should be handled.
|
|
||||||
///
|
|
||||||
/// A [TextOverflow] can be passed to [Text] and [RichText] via their
|
|
||||||
/// [Text.overflow] and [RichText.overflow] properties respectively.
|
|
||||||
enum TextOverflow {
|
|
||||||
/// Clip the overflowing text to fix its container.
|
|
||||||
clip,
|
|
||||||
|
|
||||||
/// Fade the overflowing text to transparent.
|
|
||||||
fade,
|
|
||||||
|
|
||||||
/// Use an ellipsis to indicate that the text has overflowed.
|
|
||||||
ellipsis,
|
|
||||||
|
|
||||||
/// Render overflowing text outside of its container.
|
|
||||||
visible,
|
|
||||||
}
|
|
||||||
|
|
||||||
const String _kEllipsis = '\u2026';
|
const String _kEllipsis = '\u2026';
|
||||||
|
|
||||||
/// Parent data for use with [RenderParagraph].
|
/// Parent data for use with [RenderParagraph].
|
||||||
|
@ -467,7 +467,8 @@ class Text extends StatelessWidget {
|
|||||||
|
|
||||||
/// How visual overflow should be handled.
|
/// How visual overflow should be handled.
|
||||||
///
|
///
|
||||||
/// Defaults to retrieving the value from the nearest [DefaultTextStyle] ancestor.
|
/// If this is null [TextStyle.overflow] will be used, otherwise the value
|
||||||
|
/// from the nearest [DefaultTextStyle] ancestor will be used.
|
||||||
final TextOverflow? overflow;
|
final TextOverflow? overflow;
|
||||||
|
|
||||||
/// The number of font pixels for each logical pixel.
|
/// The number of font pixels for each logical pixel.
|
||||||
@ -526,7 +527,7 @@ class Text extends StatelessWidget {
|
|||||||
textDirection: textDirection, // RichText uses Directionality.of to obtain a default if this is null.
|
textDirection: textDirection, // RichText uses Directionality.of to obtain a default if this is null.
|
||||||
locale: locale, // RichText uses Localizations.localeOf to obtain a default if this is null
|
locale: locale, // RichText uses Localizations.localeOf to obtain a default if this is null
|
||||||
softWrap: softWrap ?? defaultTextStyle.softWrap,
|
softWrap: softWrap ?? defaultTextStyle.softWrap,
|
||||||
overflow: overflow ?? defaultTextStyle.overflow,
|
overflow: overflow ?? effectiveTextStyle?.overflow ?? defaultTextStyle.overflow,
|
||||||
textScaleFactor: textScaleFactor ?? MediaQuery.textScaleFactorOf(context),
|
textScaleFactor: textScaleFactor ?? MediaQuery.textScaleFactorOf(context),
|
||||||
maxLines: maxLines ?? defaultTextStyle.maxLines,
|
maxLines: maxLines ?? defaultTextStyle.maxLines,
|
||||||
strutStyle: strutStyle,
|
strutStyle: strutStyle,
|
||||||
|
@ -744,6 +744,8 @@ class _TextStyleProxy implements TextStyle {
|
|||||||
List<Shadow>? get shadows => _delegate.shadows;
|
List<Shadow>? get shadows => _delegate.shadows;
|
||||||
@override
|
@override
|
||||||
List<ui.FontFeature>? get fontFeatures => _delegate.fontFeatures;
|
List<ui.FontFeature>? get fontFeatures => _delegate.fontFeatures;
|
||||||
|
@override
|
||||||
|
TextOverflow? get overflow => _delegate.overflow;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) =>
|
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) =>
|
||||||
@ -785,6 +787,7 @@ class _TextStyleProxy implements TextStyle {
|
|||||||
Locale? locale,
|
Locale? locale,
|
||||||
List<ui.Shadow>? shadows,
|
List<ui.Shadow>? shadows,
|
||||||
List<ui.FontFeature>? fontFeatures,
|
List<ui.FontFeature>? fontFeatures,
|
||||||
|
TextOverflow? overflow,
|
||||||
}) {
|
}) {
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
@ -819,6 +822,7 @@ class _TextStyleProxy implements TextStyle {
|
|||||||
TextDecorationStyle? decorationStyle,
|
TextDecorationStyle? decorationStyle,
|
||||||
double? decorationThickness,
|
double? decorationThickness,
|
||||||
String? debugLabel,
|
String? debugLabel,
|
||||||
|
TextOverflow? overflow,
|
||||||
}) {
|
}) {
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
|
@ -1248,6 +1248,21 @@ void main() {
|
|||||||
// The inline spans are rendered in one vertical run, the widest one determines the min intrinsic width.
|
// The inline spans are rendered in one vertical run, the widest one determines the min intrinsic width.
|
||||||
expect(paragraph.getMinIntrinsicWidth(0.0), 200);
|
expect(paragraph.getMinIntrinsicWidth(0.0), 200);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Text uses TextStyle.overflow', (WidgetTester tester) async {
|
||||||
|
const TextOverflow overflow = TextOverflow.fade;
|
||||||
|
|
||||||
|
await tester.pumpWidget( const Text(
|
||||||
|
'Hello World',
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
style: TextStyle(overflow: overflow),
|
||||||
|
));
|
||||||
|
|
||||||
|
final RichText richText = tester.firstWidget(find.byType(RichText));
|
||||||
|
|
||||||
|
expect(richText.overflow, overflow);
|
||||||
|
expect(richText.text.style!.overflow, overflow);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _pumpTextWidget({
|
Future<void> _pumpTextWidget({
|
||||||
|
Loading…
x
Reference in New Issue
Block a user