parent
4d8f38e538
commit
36d437d6f2
@ -209,7 +209,13 @@ class AppBar extends StatelessWidget {
|
||||
toolBarRow.add(new Flexible(
|
||||
child: new Padding(
|
||||
padding: new EdgeInsets.only(left: 8.0),
|
||||
child: title != null ? new DefaultTextStyle(style: centerStyle, child: title) : null
|
||||
child: title != null ?
|
||||
new DefaultTextStyle(
|
||||
style: centerStyle,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
child: title
|
||||
) : null
|
||||
)
|
||||
));
|
||||
if (actions != null)
|
||||
|
@ -345,7 +345,12 @@ class _Tab extends StatelessWidget {
|
||||
Widget _buildLabelText() {
|
||||
assert(label.text != null);
|
||||
TextStyle style = new TextStyle(color: color);
|
||||
return new Text(label.text, style: style);
|
||||
return new Text(
|
||||
label.text,
|
||||
style: style,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.fade
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLabelIcon(BuildContext context) {
|
||||
@ -371,15 +376,15 @@ class _Tab extends StatelessWidget {
|
||||
labelContent = _buildLabelIcon(context);
|
||||
} else {
|
||||
labelContent = new Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
new Container(
|
||||
child: _buildLabelIcon(context),
|
||||
margin: const EdgeInsets.only(bottom: 10.0)
|
||||
),
|
||||
_buildLabelText()
|
||||
],
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -2,20 +2,42 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
|
||||
import 'box.dart';
|
||||
import 'object.dart';
|
||||
import 'semantics.dart';
|
||||
|
||||
/// How overflowing text should be handled.
|
||||
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,
|
||||
}
|
||||
|
||||
/// A render object that displays a paragraph of text
|
||||
class RenderParagraph extends RenderBox {
|
||||
|
||||
/// Creates a paragraph render object.
|
||||
///
|
||||
/// The [text], [overflow], and [softWrap] arguments must not be null.
|
||||
RenderParagraph(TextSpan text, {
|
||||
TextAlign textAlign
|
||||
}) : _textPainter = new TextPainter(text: text, textAlign: textAlign) {
|
||||
TextAlign textAlign,
|
||||
TextOverflow overflow: TextOverflow.clip,
|
||||
bool softWrap: true
|
||||
}) : _softWrap = softWrap,
|
||||
_overflow = overflow,
|
||||
_textPainter = new TextPainter(text: text, textAlign: textAlign) {
|
||||
assert(text != null);
|
||||
assert(text.debugAssertValid());
|
||||
assert(overflow != null);
|
||||
assert(softWrap != null);
|
||||
}
|
||||
|
||||
final TextPainter _textPainter;
|
||||
@ -27,6 +49,8 @@ class RenderParagraph extends RenderBox {
|
||||
if (_textPainter.text == value)
|
||||
return;
|
||||
_textPainter.text = value;
|
||||
_overflowPainter = null;
|
||||
_overflowShader = null;
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
||||
@ -39,10 +63,34 @@ class RenderParagraph extends RenderBox {
|
||||
markNeedsPaint();
|
||||
}
|
||||
|
||||
/// Whether the text should break at soft line breaks.
|
||||
///
|
||||
/// If false, the glyphs in the text will be positioned as if there was unlimited horizontal space.
|
||||
bool get softWrap => _softWrap;
|
||||
bool _softWrap;
|
||||
void set softWrap(bool value) {
|
||||
assert(value != null);
|
||||
if (_softWrap == value)
|
||||
return;
|
||||
_softWrap = value;
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
||||
/// How visual overflow should be handled.
|
||||
TextOverflow get overflow => _overflow;
|
||||
TextOverflow _overflow;
|
||||
void set overflow(TextOverflow value) {
|
||||
assert(value != null);
|
||||
if (_overflow == value)
|
||||
return;
|
||||
_overflow = value;
|
||||
markNeedsPaint();
|
||||
}
|
||||
|
||||
void _layoutText(BoxConstraints constraints) {
|
||||
assert(constraints != null);
|
||||
assert(constraints.debugAssertIsValid());
|
||||
_textPainter.layout(minWidth: constraints.minWidth, maxWidth: constraints.maxWidth);
|
||||
_textPainter.layout(minWidth: constraints.minWidth, maxWidth: _softWrap ? constraints.maxWidth : double.INFINITY);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -95,10 +143,49 @@ class RenderParagraph extends RenderBox {
|
||||
span?.recognizer?.addPointer(event);
|
||||
}
|
||||
|
||||
bool _hasVisualOverflow = false;
|
||||
TextPainter _overflowPainter;
|
||||
ui.Shader _overflowShader;
|
||||
|
||||
@override
|
||||
void performLayout() {
|
||||
_layoutText(constraints);
|
||||
size = constraints.constrain(_textPainter.size);
|
||||
|
||||
final bool didOverflowWidth = size.width < _textPainter.width;
|
||||
// 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
|
||||
// visual overflow when there actually is visual overflow. This can become
|
||||
// a problem if we start having horizontal overflow and introduce a clip
|
||||
// that affects the actual (but undetected) vertical overflow.
|
||||
_hasVisualOverflow = didOverflowWidth || size.height < _textPainter.height;
|
||||
if (didOverflowWidth) {
|
||||
switch (_overflow) {
|
||||
case TextOverflow.clip:
|
||||
_overflowPainter = null;
|
||||
_overflowShader = null;
|
||||
break;
|
||||
case TextOverflow.fade:
|
||||
case TextOverflow.ellipsis:
|
||||
_overflowPainter ??= new TextPainter(
|
||||
text: new TextSpan(style: _textPainter.text.style, text: '\u2026')
|
||||
)..layout();
|
||||
final double overflowUnit = _overflowPainter.width;
|
||||
double fadeEnd = size.width;
|
||||
if (_overflow == TextOverflow.ellipsis)
|
||||
fadeEnd -= overflowUnit / 2.0;
|
||||
final double fadeStart = fadeEnd - _overflowPainter.width;
|
||||
// TODO(abarth): This shader has an LTR bias.
|
||||
_overflowShader = new ui.Gradient.linear(
|
||||
<Point>[new Point(fadeStart, 0.0), new Point(fadeEnd, 0.0)],
|
||||
<Color>[const Color(0xFFFFFFFF), const Color(0x00FFFFFF)]
|
||||
);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
_overflowPainter = null;
|
||||
_overflowShader = null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@ -114,7 +201,31 @@ class RenderParagraph extends RenderBox {
|
||||
// If you remove this call, make sure that changing the textAlign still
|
||||
// works properly.
|
||||
_layoutText(constraints);
|
||||
_textPainter.paint(context.canvas, offset);
|
||||
final Canvas canvas = context.canvas;
|
||||
if (_hasVisualOverflow) {
|
||||
final Rect bounds = offset & size;
|
||||
if (_overflowPainter != null)
|
||||
canvas.saveLayer(bounds, new Paint());
|
||||
else
|
||||
canvas.save();
|
||||
canvas.clipRect(bounds);
|
||||
}
|
||||
_textPainter.paint(canvas, offset);
|
||||
if (_hasVisualOverflow) {
|
||||
if (_overflowShader != null) {
|
||||
canvas.translate(offset.dx, offset.dy);
|
||||
Paint paint = new Paint()
|
||||
..transferMode = TransferMode.modulate
|
||||
..shader = _overflowShader;
|
||||
canvas.drawRect(Point.origin & size, paint);
|
||||
if (_overflow == TextOverflow.ellipsis) {
|
||||
// TODO(abarth): This paint offset has an LTR bias.
|
||||
Offset ellipseOffset = new Offset(size.width - _overflowPainter.width, 0.0);
|
||||
_overflowPainter.paint(canvas, ellipseOffset);
|
||||
}
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -45,6 +45,7 @@ export 'package:flutter/rendering.dart' show
|
||||
RenderObjectPainter,
|
||||
ShaderCallback,
|
||||
SingleChildLayoutDelegate,
|
||||
TextOverflow,
|
||||
ValueChanged,
|
||||
ViewportAnchor,
|
||||
ViewportDimensions,
|
||||
@ -1904,8 +1905,16 @@ class RichText extends LeafRenderObjectWidget {
|
||||
/// Creates a paragraph of rich text.
|
||||
///
|
||||
/// The [text] argument is required to be non-null.
|
||||
RichText({ Key key, this.text, this.textAlign }) : super(key: key) {
|
||||
RichText({
|
||||
Key key,
|
||||
this.text,
|
||||
this.textAlign,
|
||||
this.softWrap: true,
|
||||
this.overflow: TextOverflow.clip
|
||||
}) : super(key: key) {
|
||||
assert(text != null);
|
||||
assert(softWrap != null);
|
||||
assert(overflow != null);
|
||||
}
|
||||
|
||||
/// The text to display in this widget.
|
||||
@ -1914,16 +1923,30 @@ class RichText extends LeafRenderObjectWidget {
|
||||
/// How the text should be aligned horizontally.
|
||||
final TextAlign textAlign;
|
||||
|
||||
/// Whether the text should break at soft line breaks.
|
||||
///
|
||||
/// If false, the glyphs in the text will be positioned as if there was unlimited horizontal space.
|
||||
final bool softWrap;
|
||||
|
||||
/// How visual overflow should be handled.
|
||||
final TextOverflow overflow;
|
||||
|
||||
@override
|
||||
RenderParagraph createRenderObject(BuildContext context) {
|
||||
return new RenderParagraph(text, textAlign: textAlign);
|
||||
return new RenderParagraph(text,
|
||||
textAlign: textAlign,
|
||||
softWrap: softWrap,
|
||||
overflow: overflow
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void updateRenderObject(BuildContext context, RenderParagraph renderObject) {
|
||||
renderObject
|
||||
..text = text
|
||||
..textAlign = textAlign;
|
||||
..textAlign = textAlign
|
||||
..softWrap = softWrap
|
||||
..overflow = overflow;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1937,16 +1960,24 @@ class DefaultTextStyle extends InheritedWidget {
|
||||
Key key,
|
||||
this.style,
|
||||
this.textAlign,
|
||||
this.softWrap: true,
|
||||
this.overflow: TextOverflow.clip,
|
||||
Widget child
|
||||
}) : super(key: key, child: child) {
|
||||
assert(style != null);
|
||||
assert(softWrap != null);
|
||||
assert(overflow != null);
|
||||
assert(child != null);
|
||||
}
|
||||
|
||||
/// A const-constructible default text style that provides fallback values.
|
||||
///
|
||||
/// Returned from [of] when the given [BuildContext] doesn't have an enclosing default text style.
|
||||
const DefaultTextStyle.fallback() : style = const TextStyle(), textAlign = null;
|
||||
const DefaultTextStyle.fallback()
|
||||
: style = const TextStyle(),
|
||||
textAlign = null,
|
||||
softWrap = true,
|
||||
overflow = TextOverflow.clip;
|
||||
|
||||
/// Creates a default text style that inherits from the given [BuildContext].
|
||||
///
|
||||
@ -1959,6 +1990,8 @@ class DefaultTextStyle extends InheritedWidget {
|
||||
BuildContext context,
|
||||
TextStyle style,
|
||||
TextAlign textAlign,
|
||||
bool softWrap,
|
||||
TextOverflow overflow,
|
||||
Widget child
|
||||
}) {
|
||||
DefaultTextStyle parent = DefaultTextStyle.of(context);
|
||||
@ -1966,6 +1999,8 @@ class DefaultTextStyle extends InheritedWidget {
|
||||
key: key,
|
||||
style: parent.style.merge(style),
|
||||
textAlign: textAlign ?? parent.textAlign,
|
||||
softWrap: softWrap ?? parent.softWrap,
|
||||
overflow: overflow ?? parent.overflow,
|
||||
child: child
|
||||
);
|
||||
}
|
||||
@ -1976,6 +2011,14 @@ class DefaultTextStyle extends InheritedWidget {
|
||||
/// How the text should be aligned horizontally.
|
||||
final TextAlign textAlign;
|
||||
|
||||
/// Whether the text should break at soft line breaks.
|
||||
///
|
||||
/// If false, the glyphs in the text will be positioned as if there was unlimited horizontal space.
|
||||
final bool softWrap;
|
||||
|
||||
/// How visual overflow should be handled.
|
||||
final TextOverflow overflow;
|
||||
|
||||
/// The closest instance of this class that encloses the given context.
|
||||
///
|
||||
/// If no such instance exists, returns an instance created by
|
||||
@ -2019,7 +2062,13 @@ class Text extends StatelessWidget {
|
||||
///
|
||||
/// If the [style] argument is null, the text will use the style from the
|
||||
/// closest enclosing [DefaultTextStyle].
|
||||
Text(this.data, { Key key, this.style, this.textAlign }) : super(key: key) {
|
||||
Text(this.data, {
|
||||
Key key,
|
||||
this.style,
|
||||
this.textAlign,
|
||||
this.softWrap,
|
||||
this.overflow
|
||||
}) : super(key: key) {
|
||||
assert(data != null);
|
||||
}
|
||||
|
||||
@ -2036,21 +2085,24 @@ class Text extends StatelessWidget {
|
||||
/// How the text should be aligned horizontally.
|
||||
final TextAlign textAlign;
|
||||
|
||||
/// Whether the text should break at soft line breaks.
|
||||
///
|
||||
/// If false, the glyphs in the text will be positioned as if there was unlimited horizontal space.
|
||||
final bool softWrap;
|
||||
|
||||
/// How visual overflow should be handled.
|
||||
final TextOverflow overflow;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
DefaultTextStyle defaultTextStyle;
|
||||
DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context);
|
||||
TextStyle effectiveTextStyle = style;
|
||||
if (style == null || style.inherit) {
|
||||
defaultTextStyle ??= DefaultTextStyle.of(context);
|
||||
if (style == null || style.inherit)
|
||||
effectiveTextStyle = defaultTextStyle.style.merge(style);
|
||||
}
|
||||
TextAlign effectiveTextAlign = textAlign;
|
||||
if (effectiveTextAlign == null) {
|
||||
defaultTextStyle ??= DefaultTextStyle.of(context);
|
||||
effectiveTextAlign = defaultTextStyle.textAlign;
|
||||
}
|
||||
return new RichText(
|
||||
textAlign: effectiveTextAlign,
|
||||
textAlign: textAlign ?? defaultTextStyle.textAlign,
|
||||
softWrap: softWrap ?? defaultTextStyle.softWrap,
|
||||
overflow: overflow ?? defaultTextStyle.overflow,
|
||||
text: new TextSpan(
|
||||
style: effectiveTextStyle,
|
||||
text: data
|
||||
|
Loading…
x
Reference in New Issue
Block a user