mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Add support for specifying maxLines for Text. (#7493)
Overflow handling works with clipping, adding an ellipsis on the last line, or fading the last line. Fixes https://github.com/flutter/flutter/issues/7271
This commit is contained in:
parent
60847a1ded
commit
75f39789c7
@ -1 +1 @@
|
|||||||
b3ed79122edd7172327ce415688ef674d6a7fa5d
|
2efc78cc24eac9439a5315ed9333fa8599aab3a1
|
||||||
|
@ -11,6 +11,8 @@ import 'basic_types.dart';
|
|||||||
import 'text_editing.dart';
|
import 'text_editing.dart';
|
||||||
import 'text_span.dart';
|
import 'text_span.dart';
|
||||||
|
|
||||||
|
final String _kZeroWidthSpace = new String.fromCharCode(0x200B);
|
||||||
|
|
||||||
/// An object that paints a [TextSpan] tree into a [Canvas].
|
/// An object that paints a [TextSpan] tree into a [Canvas].
|
||||||
///
|
///
|
||||||
/// To use a [TextPainter], follow these steps:
|
/// To use a [TextPainter], follow these steps:
|
||||||
@ -34,8 +36,9 @@ class TextPainter {
|
|||||||
TextSpan text,
|
TextSpan text,
|
||||||
TextAlign textAlign,
|
TextAlign textAlign,
|
||||||
double textScaleFactor: 1.0,
|
double textScaleFactor: 1.0,
|
||||||
|
int maxLines,
|
||||||
String ellipsis,
|
String ellipsis,
|
||||||
}) : _text = text, _textAlign = textAlign, _textScaleFactor = textScaleFactor, _ellipsis = ellipsis {
|
}) : _text = text, _textAlign = textAlign, _textScaleFactor = textScaleFactor, _maxLines = maxLines, _ellipsis = ellipsis {
|
||||||
assert(text == null || text.debugAssertIsValid());
|
assert(text == null || text.debugAssertIsValid());
|
||||||
assert(textScaleFactor != null);
|
assert(textScaleFactor != null);
|
||||||
}
|
}
|
||||||
@ -50,6 +53,8 @@ class TextPainter {
|
|||||||
assert(value == null || value.debugAssertIsValid());
|
assert(value == null || value.debugAssertIsValid());
|
||||||
if (_text == value)
|
if (_text == value)
|
||||||
return;
|
return;
|
||||||
|
if (_text?.style != value?.style)
|
||||||
|
_layoutTemplate = null;
|
||||||
_text = value;
|
_text = value;
|
||||||
_paragraph = null;
|
_paragraph = null;
|
||||||
_needsLayout = true;
|
_needsLayout = true;
|
||||||
@ -95,6 +100,32 @@ class TextPainter {
|
|||||||
_needsLayout = true;
|
_needsLayout = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An optional maximum number of lines for the text to span, wrapping if necessary.
|
||||||
|
/// If the text exceeds the given number of lines, it will be truncated according
|
||||||
|
/// to [overflow].
|
||||||
|
int get maxLines => _maxLines;
|
||||||
|
int _maxLines;
|
||||||
|
set maxLines(int value) {
|
||||||
|
if (_maxLines == value)
|
||||||
|
return;
|
||||||
|
_maxLines = value;
|
||||||
|
_paragraph = null;
|
||||||
|
_needsLayout = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Paragraph _layoutTemplate;
|
||||||
|
double get preferredLineHeight {
|
||||||
|
assert(text != null);
|
||||||
|
if (_layoutTemplate == null) {
|
||||||
|
ui.ParagraphBuilder builder = new ui.ParagraphBuilder(new ui.ParagraphStyle());
|
||||||
|
if (text.style != null)
|
||||||
|
builder.pushStyle(text.style.getTextStyle(textScaleFactor: textScaleFactor));
|
||||||
|
builder.addText(_kZeroWidthSpace);
|
||||||
|
_layoutTemplate = builder.build()
|
||||||
|
..layout(new ui.ParagraphConstraints(width: double.INFINITY));
|
||||||
|
}
|
||||||
|
return _layoutTemplate.height;
|
||||||
|
}
|
||||||
|
|
||||||
// Unfortunately, using full precision floating point here causes bad layouts
|
// Unfortunately, using full precision floating point here causes bad layouts
|
||||||
// because floating point math isn't associative. If we add and subtract
|
// because floating point math isn't associative. If we add and subtract
|
||||||
@ -162,6 +193,11 @@ class TextPainter {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool get didExceedMaxLines {
|
||||||
|
assert(!_needsLayout);
|
||||||
|
return _paragraph.didExceedMaxLines;
|
||||||
|
}
|
||||||
|
|
||||||
double _lastMinWidth;
|
double _lastMinWidth;
|
||||||
double _lastMaxWidth;
|
double _lastMaxWidth;
|
||||||
|
|
||||||
@ -179,9 +215,14 @@ class TextPainter {
|
|||||||
ui.ParagraphStyle paragraphStyle = _text.style?.getParagraphStyle(
|
ui.ParagraphStyle paragraphStyle = _text.style?.getParagraphStyle(
|
||||||
textAlign: textAlign,
|
textAlign: textAlign,
|
||||||
textScaleFactor: textScaleFactor,
|
textScaleFactor: textScaleFactor,
|
||||||
|
maxLines: _maxLines,
|
||||||
ellipsis: _ellipsis,
|
ellipsis: _ellipsis,
|
||||||
);
|
);
|
||||||
paragraphStyle ??= new ui.ParagraphStyle();
|
paragraphStyle ??= new ui.ParagraphStyle(
|
||||||
|
textAlign: textAlign,
|
||||||
|
maxLines: maxLines,
|
||||||
|
ellipsis: ellipsis,
|
||||||
|
);
|
||||||
ui.ParagraphBuilder builder = new ui.ParagraphBuilder(paragraphStyle);
|
ui.ParagraphBuilder builder = new ui.ParagraphBuilder(paragraphStyle);
|
||||||
_text.build(builder, textScaleFactor: textScaleFactor);
|
_text.build(builder, textScaleFactor: textScaleFactor);
|
||||||
_paragraph = builder.build();
|
_paragraph = builder.build();
|
||||||
|
@ -233,6 +233,7 @@ class TextStyle {
|
|||||||
TextAlign textAlign,
|
TextAlign textAlign,
|
||||||
double textScaleFactor: 1.0,
|
double textScaleFactor: 1.0,
|
||||||
String ellipsis,
|
String ellipsis,
|
||||||
|
int maxLines,
|
||||||
}) {
|
}) {
|
||||||
return new ui.ParagraphStyle(
|
return new ui.ParagraphStyle(
|
||||||
textAlign: textAlign,
|
textAlign: textAlign,
|
||||||
@ -241,6 +242,7 @@ class TextStyle {
|
|||||||
fontFamily: fontFamily,
|
fontFamily: fontFamily,
|
||||||
fontSize: fontSize == null ? null : fontSize * textScaleFactor,
|
fontSize: fontSize == null ? null : fontSize * textScaleFactor,
|
||||||
lineHeight: height,
|
lineHeight: height,
|
||||||
|
maxLines: maxLines,
|
||||||
ellipsis: ellipsis,
|
ellipsis: ellipsis,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:ui' as ui show Paragraph, ParagraphBuilder, ParagraphConstraints, ParagraphStyle, TextBox;
|
import 'dart:ui' as ui show TextBox;
|
||||||
|
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
|
|
||||||
@ -88,9 +88,6 @@ class RenderEditable extends RenderBox {
|
|||||||
set text(TextSpan value) {
|
set text(TextSpan value) {
|
||||||
if (_textPainter.text == value)
|
if (_textPainter.text == value)
|
||||||
return;
|
return;
|
||||||
TextSpan oldStyledText = _textPainter.text;
|
|
||||||
if (oldStyledText.style != value.style)
|
|
||||||
_layoutTemplate = null;
|
|
||||||
_textPainter.text = value;
|
_textPainter.text = value;
|
||||||
markNeedsLayout();
|
markNeedsLayout();
|
||||||
}
|
}
|
||||||
@ -115,7 +112,9 @@ class RenderEditable extends RenderBox {
|
|||||||
markNeedsPaint();
|
markNeedsPaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether to paint the cursor.
|
/// The maximum number of lines for the text to span, wrapping if necessary.
|
||||||
|
/// If this is 1 (the default), the text will not wrap, but will extend
|
||||||
|
/// indefinitely instead.
|
||||||
int get maxLines => _maxLines;
|
int get maxLines => _maxLines;
|
||||||
int _maxLines;
|
int _maxLines;
|
||||||
set maxLines(int value) {
|
set maxLines(int value) {
|
||||||
@ -222,19 +221,7 @@ class RenderEditable extends RenderBox {
|
|||||||
|
|
||||||
Size _contentSize;
|
Size _contentSize;
|
||||||
|
|
||||||
ui.Paragraph _layoutTemplate;
|
double get _preferredLineHeight => _textPainter.preferredLineHeight;
|
||||||
double get _preferredLineHeight {
|
|
||||||
if (_layoutTemplate == null) {
|
|
||||||
ui.ParagraphBuilder builder = new ui.ParagraphBuilder(new ui.ParagraphStyle())
|
|
||||||
..pushStyle(text.style.getTextStyle(textScaleFactor: textScaleFactor))
|
|
||||||
..addText(_kZeroWidthSpace);
|
|
||||||
// TODO(abarth): ParagraphBuilder#build's argument should be optional.
|
|
||||||
// TODO(abarth): These min/max values should be the default for ui.Paragraph.
|
|
||||||
_layoutTemplate = builder.build()
|
|
||||||
..layout(new ui.ParagraphConstraints(width: double.INFINITY));
|
|
||||||
}
|
|
||||||
return _layoutTemplate.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
double get _maxContentWidth {
|
double get _maxContentWidth {
|
||||||
return _maxLines > 1 ?
|
return _maxLines > 1 ?
|
||||||
|
@ -33,13 +33,15 @@ class RenderParagraph extends RenderBox {
|
|||||||
TextAlign textAlign,
|
TextAlign textAlign,
|
||||||
bool softWrap: true,
|
bool softWrap: true,
|
||||||
TextOverflow overflow: TextOverflow.clip,
|
TextOverflow overflow: TextOverflow.clip,
|
||||||
double textScaleFactor: 1.0
|
double textScaleFactor: 1.0,
|
||||||
|
int maxLines,
|
||||||
}) : _softWrap = softWrap,
|
}) : _softWrap = softWrap,
|
||||||
_overflow = overflow,
|
_overflow = overflow,
|
||||||
_textPainter = new TextPainter(
|
_textPainter = new TextPainter(
|
||||||
text: text,
|
text: text,
|
||||||
textAlign: textAlign,
|
textAlign: textAlign,
|
||||||
textScaleFactor: textScaleFactor,
|
textScaleFactor: textScaleFactor,
|
||||||
|
maxLines: maxLines,
|
||||||
ellipsis: overflow == TextOverflow.ellipsis ? _kEllipsis : null,
|
ellipsis: overflow == TextOverflow.ellipsis ? _kEllipsis : null,
|
||||||
) {
|
) {
|
||||||
assert(text != null);
|
assert(text != null);
|
||||||
@ -110,8 +112,20 @@ class RenderParagraph extends RenderBox {
|
|||||||
markNeedsLayout();
|
markNeedsLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An optional maximum number of lines for the text to span, wrapping if necessary.
|
||||||
|
/// If the text exceeds the given number of lines, it will be truncated according
|
||||||
|
/// to [overflow].
|
||||||
|
int get maxLines => _textPainter.maxLines;
|
||||||
|
set maxLines(int value) {
|
||||||
|
if (_textPainter.maxLines == value)
|
||||||
|
return;
|
||||||
|
_textPainter.maxLines = value;
|
||||||
|
_overflowShader = null;
|
||||||
|
markNeedsLayout();
|
||||||
|
}
|
||||||
|
|
||||||
void _layoutText({ double minWidth: 0.0, double maxWidth: double.INFINITY }) {
|
void _layoutText({ double minWidth: 0.0, double maxWidth: double.INFINITY }) {
|
||||||
bool wrap = _softWrap || _overflow == TextOverflow.ellipsis;
|
bool wrap = _softWrap || (_overflow == TextOverflow.ellipsis && maxLines == null);
|
||||||
_textPainter.layout(minWidth: minWidth, maxWidth: wrap ? maxWidth : double.INFINITY);
|
_textPainter.layout(minWidth: minWidth, maxWidth: wrap ? maxWidth : double.INFINITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,30 +197,40 @@ class RenderParagraph extends RenderBox {
|
|||||||
size = constraints.constrain(textSize);
|
size = constraints.constrain(textSize);
|
||||||
|
|
||||||
final bool didOverflowWidth = size.width < textSize.width;
|
final bool didOverflowWidth = size.width < textSize.width;
|
||||||
|
final bool didOverflowHeight = _textPainter.didExceedMaxLines;
|
||||||
// TODO(abarth): We're only measuring the sizes of the line boxes here. If
|
// TODO(abarth): We're only measuring the sizes of the line boxes here. If
|
||||||
// the glyphs draw outside the line boxes, we might think that there isn't
|
// the glyphs draw outside the line boxes, we might think that there isn't
|
||||||
// visual overflow when there actually is visual overflow. This can become
|
// visual overflow when there actually is visual overflow. This can become
|
||||||
// a problem if we start having horizontal overflow and introduce a clip
|
// a problem if we start having horizontal overflow and introduce a clip
|
||||||
// that affects the actual (but undetected) vertical overflow.
|
// that affects the actual (but undetected) vertical overflow.
|
||||||
_hasVisualOverflow = didOverflowWidth || size.height < textSize.height;
|
_hasVisualOverflow = didOverflowWidth || didOverflowHeight;
|
||||||
if (didOverflowWidth) {
|
if (_hasVisualOverflow) {
|
||||||
switch (_overflow) {
|
switch (_overflow) {
|
||||||
case TextOverflow.clip:
|
case TextOverflow.clip:
|
||||||
case TextOverflow.ellipsis:
|
case TextOverflow.ellipsis:
|
||||||
_overflowShader = null;
|
_overflowShader = null;
|
||||||
break;
|
break;
|
||||||
case TextOverflow.fade:
|
case TextOverflow.fade:
|
||||||
TextPainter fadeWidthPainter = new TextPainter(
|
TextPainter fadeSizePainter = new TextPainter(
|
||||||
text: new TextSpan(style: _textPainter.text.style, text: '\u2026'),
|
text: new TextSpan(style: _textPainter.text.style, text: '\u2026'),
|
||||||
textScaleFactor: textScaleFactor
|
textScaleFactor: textScaleFactor
|
||||||
)..layout();
|
)..layout();
|
||||||
|
if (didOverflowWidth) {
|
||||||
final double fadeEnd = size.width;
|
final double fadeEnd = size.width;
|
||||||
final double fadeStart = fadeEnd - fadeWidthPainter.width;
|
final double fadeStart = fadeEnd - fadeSizePainter.width;
|
||||||
// TODO(abarth): This shader has an LTR bias.
|
// TODO(abarth): This shader has an LTR bias.
|
||||||
_overflowShader = new ui.Gradient.linear(
|
_overflowShader = new ui.Gradient.linear(
|
||||||
<Point>[new Point(fadeStart, 0.0), new Point(fadeEnd, 0.0)],
|
<Point>[new Point(fadeStart, 0.0), new Point(fadeEnd, 0.0)],
|
||||||
<Color>[const Color(0xFFFFFFFF), const Color(0x00FFFFFF)]
|
<Color>[const Color(0xFFFFFFFF), const Color(0x00FFFFFF)]
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
final double fadeEnd = size.height;
|
||||||
|
final double fadeStart = fadeEnd - fadeSizePainter.height / 2.0;
|
||||||
|
_overflowShader = new ui.Gradient.linear(
|
||||||
|
<Point>[new Point(0.0, fadeStart), new Point(0.0, fadeEnd)],
|
||||||
|
<Color>[const Color(0xFFFFFFFF), const Color(0x00FFFFFF)]
|
||||||
|
);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -2442,7 +2442,8 @@ class RichText extends LeafRenderObjectWidget {
|
|||||||
this.textAlign,
|
this.textAlign,
|
||||||
this.softWrap: true,
|
this.softWrap: true,
|
||||||
this.overflow: TextOverflow.clip,
|
this.overflow: TextOverflow.clip,
|
||||||
this.textScaleFactor: 1.0
|
this.textScaleFactor: 1.0,
|
||||||
|
this.maxLines,
|
||||||
}) : super(key: key) {
|
}) : super(key: key) {
|
||||||
assert(text != null);
|
assert(text != null);
|
||||||
assert(softWrap != null);
|
assert(softWrap != null);
|
||||||
@ -2470,13 +2471,19 @@ class RichText extends LeafRenderObjectWidget {
|
|||||||
/// the specified font size.
|
/// the specified font size.
|
||||||
final double textScaleFactor;
|
final double textScaleFactor;
|
||||||
|
|
||||||
|
/// An optional maximum number of lines for the text to span, wrapping if necessary.
|
||||||
|
/// If the text exceeds the given number of lines, it will be truncated according
|
||||||
|
/// to [overflow].
|
||||||
|
final int maxLines;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
RenderParagraph createRenderObject(BuildContext context) {
|
RenderParagraph createRenderObject(BuildContext context) {
|
||||||
return new RenderParagraph(text,
|
return new RenderParagraph(text,
|
||||||
textAlign: textAlign,
|
textAlign: textAlign,
|
||||||
softWrap: softWrap,
|
softWrap: softWrap,
|
||||||
overflow: overflow,
|
overflow: overflow,
|
||||||
textScaleFactor: textScaleFactor
|
textScaleFactor: textScaleFactor,
|
||||||
|
maxLines: maxLines,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2487,7 +2494,8 @@ class RichText extends LeafRenderObjectWidget {
|
|||||||
..textAlign = textAlign
|
..textAlign = textAlign
|
||||||
..softWrap = softWrap
|
..softWrap = softWrap
|
||||||
..overflow = overflow
|
..overflow = overflow
|
||||||
..textScaleFactor = textScaleFactor;
|
..textScaleFactor = textScaleFactor
|
||||||
|
..maxLines = maxLines;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ class DefaultTextStyle extends InheritedWidget {
|
|||||||
this.textAlign,
|
this.textAlign,
|
||||||
this.softWrap: true,
|
this.softWrap: true,
|
||||||
this.overflow: TextOverflow.clip,
|
this.overflow: TextOverflow.clip,
|
||||||
|
this.maxLines,
|
||||||
Widget child
|
Widget child
|
||||||
}) : super(key: key, child: child) {
|
}) : super(key: key, child: child) {
|
||||||
assert(style != null);
|
assert(style != null);
|
||||||
@ -35,6 +36,7 @@ class DefaultTextStyle extends InheritedWidget {
|
|||||||
: style = const TextStyle(),
|
: style = const TextStyle(),
|
||||||
textAlign = null,
|
textAlign = null,
|
||||||
softWrap = true,
|
softWrap = true,
|
||||||
|
maxLines = null,
|
||||||
overflow = TextOverflow.clip;
|
overflow = TextOverflow.clip;
|
||||||
|
|
||||||
/// Creates a default text style that inherits from the given [BuildContext].
|
/// Creates a default text style that inherits from the given [BuildContext].
|
||||||
@ -50,6 +52,7 @@ class DefaultTextStyle extends InheritedWidget {
|
|||||||
TextAlign textAlign,
|
TextAlign textAlign,
|
||||||
bool softWrap,
|
bool softWrap,
|
||||||
TextOverflow overflow,
|
TextOverflow overflow,
|
||||||
|
int maxLines,
|
||||||
Widget child
|
Widget child
|
||||||
}) {
|
}) {
|
||||||
assert(context != null);
|
assert(context != null);
|
||||||
@ -61,6 +64,7 @@ class DefaultTextStyle extends InheritedWidget {
|
|||||||
textAlign: textAlign ?? parent.textAlign,
|
textAlign: textAlign ?? parent.textAlign,
|
||||||
softWrap: softWrap ?? parent.softWrap,
|
softWrap: softWrap ?? parent.softWrap,
|
||||||
overflow: overflow ?? parent.overflow,
|
overflow: overflow ?? parent.overflow,
|
||||||
|
maxLines: maxLines ?? parent.maxLines,
|
||||||
child: child
|
child: child
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -79,6 +83,11 @@ class DefaultTextStyle extends InheritedWidget {
|
|||||||
/// How visual overflow should be handled.
|
/// How visual overflow should be handled.
|
||||||
final TextOverflow overflow;
|
final TextOverflow overflow;
|
||||||
|
|
||||||
|
/// An optional maximum number of lines for the text to span, wrapping if necessary.
|
||||||
|
/// If the text exceeds the given number of lines, it will be truncated according
|
||||||
|
/// to [overflow].
|
||||||
|
final int maxLines;
|
||||||
|
|
||||||
/// The closest instance of this class that encloses the given context.
|
/// The closest instance of this class that encloses the given context.
|
||||||
///
|
///
|
||||||
/// If no such instance exists, returns an instance created by
|
/// If no such instance exists, returns an instance created by
|
||||||
@ -134,7 +143,8 @@ class Text extends StatelessWidget {
|
|||||||
this.textAlign,
|
this.textAlign,
|
||||||
this.softWrap,
|
this.softWrap,
|
||||||
this.overflow,
|
this.overflow,
|
||||||
this.textScaleFactor
|
this.textScaleFactor,
|
||||||
|
this.maxLines,
|
||||||
}) : super(key: key) {
|
}) : super(key: key) {
|
||||||
assert(data != null);
|
assert(data != null);
|
||||||
}
|
}
|
||||||
@ -168,6 +178,11 @@ class Text extends StatelessWidget {
|
|||||||
/// Defaults to [MediaQuery.textScaleFactor].
|
/// Defaults to [MediaQuery.textScaleFactor].
|
||||||
final double textScaleFactor;
|
final double textScaleFactor;
|
||||||
|
|
||||||
|
/// An optional maximum number of lines the text is allowed to take up.
|
||||||
|
/// If the text exceeds the given number of lines, it will be truncated according
|
||||||
|
/// to [overflow].
|
||||||
|
final int maxLines;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context);
|
DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context);
|
||||||
@ -179,6 +194,7 @@ class Text extends StatelessWidget {
|
|||||||
softWrap: softWrap ?? defaultTextStyle.softWrap,
|
softWrap: softWrap ?? defaultTextStyle.softWrap,
|
||||||
overflow: overflow ?? defaultTextStyle.overflow,
|
overflow: overflow ?? defaultTextStyle.overflow,
|
||||||
textScaleFactor: textScaleFactor ?? MediaQuery.of(context).textScaleFactor,
|
textScaleFactor: textScaleFactor ?? MediaQuery.of(context).textScaleFactor,
|
||||||
|
maxLines: maxLines ?? defaultTextStyle.maxLines,
|
||||||
text: new TextSpan(
|
text: new TextSpan(
|
||||||
style: effectiveTextStyle,
|
style: effectiveTextStyle,
|
||||||
text: data
|
text: data
|
||||||
|
@ -98,9 +98,9 @@ void main() {
|
|||||||
|
|
||||||
ui.ParagraphStyle ps2 = s2.getParagraphStyle(textAlign: TextAlign.center);
|
ui.ParagraphStyle ps2 = s2.getParagraphStyle(textAlign: TextAlign.center);
|
||||||
expect(ps2, equals(new ui.ParagraphStyle(textAlign: TextAlign.center, fontWeight: FontWeight.w800, fontSize: 10.0, lineHeight: 100.0)));
|
expect(ps2, equals(new ui.ParagraphStyle(textAlign: TextAlign.center, fontWeight: FontWeight.w800, fontSize: 10.0, lineHeight: 100.0)));
|
||||||
expect(ps2.toString(), 'ParagraphStyle(textAlign: TextAlign.center, fontWeight: FontWeight.w800, fontStyle: unspecified, lineCount: unspecified, fontFamily: unspecified, fontSize: 10.0, lineHeight: 100.0x, ellipsis: unspecified)');
|
expect(ps2.toString(), 'ParagraphStyle(textAlign: TextAlign.center, fontWeight: FontWeight.w800, fontStyle: unspecified, lineCount: unspecified, fontFamily: unspecified, fontSize: 10.0, lineHeight: 100.0x, maxLines: unspecified, ellipsis: unspecified)');
|
||||||
ui.ParagraphStyle ps5 = s5.getParagraphStyle();
|
ui.ParagraphStyle ps5 = s5.getParagraphStyle();
|
||||||
expect(ps5, equals(new ui.ParagraphStyle(fontWeight: FontWeight.w700, fontSize: 12.0, lineHeight: 123.0)));
|
expect(ps5, equals(new ui.ParagraphStyle(fontWeight: FontWeight.w700, fontSize: 12.0, lineHeight: 123.0)));
|
||||||
expect(ps5.toString(), 'ParagraphStyle(textAlign: unspecified, fontWeight: FontWeight.w700, fontStyle: unspecified, lineCount: unspecified, fontFamily: unspecified, fontSize: 12.0, lineHeight: 123.0x, ellipsis: unspecified)');
|
expect(ps5.toString(), 'ParagraphStyle(textAlign: unspecified, fontWeight: FontWeight.w700, fontStyle: unspecified, lineCount: unspecified, fontFamily: unspecified, fontSize: 12.0, lineHeight: 123.0x, maxLines: unspecified, ellipsis: unspecified)');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -72,4 +72,64 @@ void main() {
|
|||||||
TextRange range85 = paragraph.getWordBoundary(new TextPosition(offset: 75));
|
TextRange range85 = paragraph.getWordBoundary(new TextPosition(offset: 75));
|
||||||
expect(range85.textInside(_kText), equals('Queen\'s'));
|
expect(range85.textInside(_kText), equals('Queen\'s'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('overflow test', () {
|
||||||
|
RenderParagraph paragraph = new RenderParagraph(
|
||||||
|
new TextSpan(text: 'This is\na wrapping test. It should wrap at manual newlines, and if softWrap is true, also at spaces.'),
|
||||||
|
maxLines: 1,
|
||||||
|
softWrap: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
void relayoutWith({int maxLines, bool softWrap, TextOverflow overflow}) {
|
||||||
|
paragraph
|
||||||
|
..maxLines = maxLines
|
||||||
|
..softWrap = softWrap
|
||||||
|
..overflow = overflow;
|
||||||
|
pumpFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lay out in a narrow box to force wrapping.
|
||||||
|
layout(paragraph, constraints: new BoxConstraints(maxWidth: 50.0));
|
||||||
|
double lineHeight = paragraph.size.height;
|
||||||
|
|
||||||
|
relayoutWith(maxLines: 3, softWrap: true, overflow: TextOverflow.clip);
|
||||||
|
expect(paragraph.size.height, equals(3 * lineHeight));
|
||||||
|
|
||||||
|
relayoutWith(maxLines: null, softWrap: true, overflow: TextOverflow.clip);
|
||||||
|
expect(paragraph.size.height, greaterThan(5 * lineHeight));
|
||||||
|
|
||||||
|
// Try again with ellipsis overflow. We can't test that the ellipsis are
|
||||||
|
// drawn, but we can test the sizing.
|
||||||
|
relayoutWith(maxLines: 1, softWrap: true, overflow: TextOverflow.ellipsis);
|
||||||
|
expect(paragraph.size.height, equals(lineHeight));
|
||||||
|
|
||||||
|
relayoutWith(maxLines: 3, softWrap: true, overflow: TextOverflow.ellipsis);
|
||||||
|
expect(paragraph.size.height, equals(3 * lineHeight));
|
||||||
|
|
||||||
|
// This is the one weird case. If maxLines is null, we would expect to allow
|
||||||
|
// infinite wrapping. However, if we did, we'd never know when to append an
|
||||||
|
// ellipsis, so this really means "append ellipsis as soon as we exceed the
|
||||||
|
// width".
|
||||||
|
relayoutWith(maxLines: null, softWrap: true, overflow: TextOverflow.ellipsis);
|
||||||
|
expect(paragraph.size.height, equals(2 * lineHeight));
|
||||||
|
|
||||||
|
// Now with no soft wrapping.
|
||||||
|
relayoutWith(maxLines: 1, softWrap: false, overflow: TextOverflow.clip);
|
||||||
|
expect(paragraph.size.height, equals(lineHeight));
|
||||||
|
|
||||||
|
relayoutWith(maxLines: 3, softWrap: false, overflow: TextOverflow.clip);
|
||||||
|
expect(paragraph.size.height, equals(2 * lineHeight));
|
||||||
|
|
||||||
|
relayoutWith(maxLines: null, softWrap: false, overflow: TextOverflow.clip);
|
||||||
|
expect(paragraph.size.height, equals(2 * lineHeight));
|
||||||
|
|
||||||
|
relayoutWith(maxLines: 1, softWrap: false, overflow: TextOverflow.ellipsis);
|
||||||
|
expect(paragraph.size.height, equals(lineHeight));
|
||||||
|
|
||||||
|
relayoutWith(maxLines: 3, softWrap: false, overflow: TextOverflow.ellipsis);
|
||||||
|
expect(paragraph.size.height, equals(2 * lineHeight));
|
||||||
|
|
||||||
|
relayoutWith(maxLines: null, softWrap: false, overflow: TextOverflow.ellipsis);
|
||||||
|
expect(paragraph.size.height, equals(2 * lineHeight));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user