Commit 8ac9cc45 authored by Adam Barth's avatar Adam Barth

Improve the docs for Text and RichText (#3507)

Fixes #3503
parent a5e794ca
...@@ -36,7 +36,15 @@ bool _deepEquals(List<Object> a, List<Object> b) { ...@@ -36,7 +36,15 @@ bool _deepEquals(List<Object> a, List<Object> b) {
/// treated as if it was an unstyled [TextSpan] at the start of the /// treated as if it was an unstyled [TextSpan] at the start of the
/// [children] list. /// [children] list.
/// ///
/// To paint a [TextSpan] on a [Canvas], use a [TextPainter]. /// To paint a [TextSpan] on a [Canvas], use a [TextPainter]. To display a text
/// span in a widget, use a [RichText]. For text with a single style, consider
/// using the [Text] widget.
///
/// See also:
///
/// * [Text]
/// * [RichText]
/// * [TextPainter]
class TextSpan { class TextSpan {
/// Creates a [TextSpan] with the given values. /// Creates a [TextSpan] with the given values.
/// ///
...@@ -102,6 +110,7 @@ class TextSpan { ...@@ -102,6 +110,7 @@ class TextSpan {
builder.pop(); builder.pop();
} }
/// Walks this text span and its decendants in pre-order and calls [visitor] for each span that has text.
bool visitTextSpan(bool visitor(TextSpan span)) { bool visitTextSpan(bool visitor(TextSpan span)) {
if (text != null) { if (text != null) {
if (!visitor(this)) if (!visitor(this))
...@@ -116,6 +125,7 @@ class TextSpan { ...@@ -116,6 +125,7 @@ class TextSpan {
return true; return true;
} }
/// Returns the text span that contains the given position in the text.
TextSpan getSpanForPosition(TextPosition position) { TextSpan getSpanForPosition(TextPosition position) {
assert(debugAssertValid()); assert(debugAssertValid());
TextAffinity affinity = position.affinity; TextAffinity affinity = position.affinity;
...@@ -238,6 +248,10 @@ class TextSpan { ...@@ -238,6 +248,10 @@ class TextSpan {
/// changes, return to step 2. If the text to be painted changes, /// changes, return to step 2. If the text to be painted changes,
/// return to step 1. /// return to step 1.
class TextPainter { class TextPainter {
/// Creates a text painter that paints the given text.
///
/// The text argument is optional but [text] must be non-null before calling
/// [layout] or [layoutToMaxIntrinsicWidth].
TextPainter([ TextSpan text ]) { TextPainter([ TextSpan text ]) {
this.text = text; this.text = text;
} }
...@@ -245,9 +259,9 @@ class TextPainter { ...@@ -245,9 +259,9 @@ class TextPainter {
ui.Paragraph _paragraph; ui.Paragraph _paragraph;
bool _needsLayout = false; bool _needsLayout = false;
TextSpan _text;
/// The (potentially styled) text to paint. /// The (potentially styled) text to paint.
TextSpan get text => _text; TextSpan get text => _text;
TextSpan _text;
void set text(TextSpan value) { void set text(TextSpan value) {
assert(value == null || value.debugAssertValid()); assert(value == null || value.debugAssertValid());
if (_text == value) if (_text == value)
...@@ -265,6 +279,8 @@ class TextPainter { ...@@ -265,6 +279,8 @@ class TextPainter {
} }
/// The minimum width at which to layout the text. /// The minimum width at which to layout the text.
///
/// Requires [layout] to be called again before painting.
double get minWidth => _paragraph.minWidth; double get minWidth => _paragraph.minWidth;
void set minWidth(double value) { void set minWidth(double value) {
if (_paragraph.minWidth == value) if (_paragraph.minWidth == value)
...@@ -274,6 +290,8 @@ class TextPainter { ...@@ -274,6 +290,8 @@ class TextPainter {
} }
/// The maximum width at which to layout the text. /// The maximum width at which to layout the text.
///
/// Requires [layout] to be called again before painting.
double get maxWidth => _paragraph.maxWidth; double get maxWidth => _paragraph.maxWidth;
void set maxWidth(double value) { void set maxWidth(double value) {
if (_paragraph.maxWidth == value) if (_paragraph.maxWidth == value)
...@@ -283,6 +301,8 @@ class TextPainter { ...@@ -283,6 +301,8 @@ class TextPainter {
} }
/// The minimum height at which to layout the text. /// The minimum height at which to layout the text.
///
/// Requires [layout] or [layoutToMaxIntrinsicWidth] to be called again before painting.
double get minHeight => _paragraph.minHeight; double get minHeight => _paragraph.minHeight;
void set minHeight(double value) { void set minHeight(double value) {
if (_paragraph.minHeight == value) if (_paragraph.minHeight == value)
...@@ -292,6 +312,8 @@ class TextPainter { ...@@ -292,6 +312,8 @@ class TextPainter {
} }
/// The maximum height at which to layout the text. /// The maximum height at which to layout the text.
///
/// Requires [layout] or [layoutToMaxIntrinsicWidth] to be called again before painting.
double get maxHeight => _paragraph.maxHeight; double get maxHeight => _paragraph.maxHeight;
void set maxHeight(double value) { void set maxHeight(double value) {
if (_paragraph.maxHeight == value) if (_paragraph.maxHeight == value)
...@@ -311,33 +333,48 @@ class TextPainter { ...@@ -311,33 +333,48 @@ class TextPainter {
} }
/// The width at which decreasing the width of the text would prevent it from painting itself completely within its bounds. /// The width at which decreasing the width of the text would prevent it from painting itself completely within its bounds.
///
/// Valid only after [layout] or [layoutToMaxIntrinsicWidth] has been called.
double get minIntrinsicWidth { double get minIntrinsicWidth {
assert(!_needsLayout); assert(!_needsLayout);
return _applyFloatingPointHack(_paragraph.minIntrinsicWidth); return _applyFloatingPointHack(_paragraph.minIntrinsicWidth);
} }
/// The width at which increasing the width of the text no longer decreases the height. /// The width at which increasing the width of the text no longer decreases the height.
///
/// Valid only after [layout] or [layoutToMaxIntrinsicWidth] has been called.
double get maxIntrinsicWidth { double get maxIntrinsicWidth {
assert(!_needsLayout); assert(!_needsLayout);
return _applyFloatingPointHack(_paragraph.maxIntrinsicWidth); return _applyFloatingPointHack(_paragraph.maxIntrinsicWidth);
} }
/// The horizontal space required to paint this text.
///
/// Valid only after [layout] or [layoutToMaxIntrinsicWidth] has been called.
double get width { double get width {
assert(!_needsLayout); assert(!_needsLayout);
return _applyFloatingPointHack(_paragraph.width); return _applyFloatingPointHack(_paragraph.width);
} }
/// The vertical space required to paint this text.
///
/// Valid only after [layout] or [layoutToMaxIntrinsicWidth] has been called.
double get height { double get height {
assert(!_needsLayout); assert(!_needsLayout);
return _applyFloatingPointHack(_paragraph.height); return _applyFloatingPointHack(_paragraph.height);
} }
/// The amount of space required to paint this text.
///
/// Valid only after [layout] or [layoutToMaxIntrinsicWidth] has been called.
Size get size { Size get size {
assert(!_needsLayout); assert(!_needsLayout);
return new Size(width, height); return new Size(width, height);
} }
/// Returns the distance from the top of the text to the first baseline of the given type. /// Returns the distance from the top of the text to the first baseline of the given type.
///
/// Valid only after [layout] or [layoutToMaxIntrinsicWidth] has been called.
double computeDistanceToActualBaseline(TextBaseline baseline) { double computeDistanceToActualBaseline(TextBaseline baseline) {
assert(!_needsLayout); assert(!_needsLayout);
switch (baseline) { switch (baseline) {
...@@ -360,6 +397,8 @@ class TextPainter { ...@@ -360,6 +397,8 @@ class TextPainter {
} }
/// Computes the visual position of the glyphs using the unconstrainted max intrinsic width. /// Computes the visual position of the glyphs using the unconstrainted max intrinsic width.
///
/// Overwrites the previously configured [minWidth] and [maxWidth] values.
void layoutToMaxIntrinsicWidth() { void layoutToMaxIntrinsicWidth() {
if (!_needsLayout && _lastLayoutWasToMaxIntrinsicWidth && width == maxIntrinsicWidth) if (!_needsLayout && _lastLayoutWasToMaxIntrinsicWidth && width == maxIntrinsicWidth)
return; return;
...@@ -378,8 +417,18 @@ class TextPainter { ...@@ -378,8 +417,18 @@ class TextPainter {
} }
/// Paints the text onto the given canvas at the given offset. /// Paints the text onto the given canvas at the given offset.
///
/// Valid only after [layout] or [layoutToMaxIntrinsicWidth] has been called.
void paint(Canvas canvas, Offset offset) { void paint(Canvas canvas, Offset offset) {
assert(!_needsLayout && "Please call layout() before paint() to position the text before painting it." is String); assert(() {
if (_needsLayout) {
throw new FlutterError(
'TextPainter.paint called when text geometry was not yet calculated.\n'
'Please call layout() before paint() to position the text before painting it.'
);
}
return true;
});
canvas.drawParagraph(_paragraph, offset); canvas.drawParagraph(_paragraph, offset);
} }
...@@ -404,6 +453,8 @@ class TextPainter { ...@@ -404,6 +453,8 @@ class TextPainter {
} }
/// Returns the offset at which to paint the caret. /// Returns the offset at which to paint the caret.
///
/// Valid only after [layout] or [layoutToMaxIntrinsicWidth] has been called.
Offset getOffsetForCaret(TextPosition position, Rect caretPrototype) { Offset getOffsetForCaret(TextPosition position, Rect caretPrototype) {
assert(!_needsLayout); assert(!_needsLayout);
int offset = position.offset; int offset = position.offset;
...@@ -431,6 +482,7 @@ class TextPainter { ...@@ -431,6 +482,7 @@ class TextPainter {
return _paragraph.getBoxesForRange(selection.start, selection.end); return _paragraph.getBoxesForRange(selection.start, selection.end);
} }
/// Returns the position within the text for the given pixel offset.
TextPosition getPositionForOffset(Offset offset) { TextPosition getPositionForOffset(Offset offset) {
assert(!_needsLayout); assert(!_needsLayout);
return _paragraph.getPositionForOffset(offset); return _paragraph.getPositionForOffset(offset);
......
...@@ -8,6 +8,7 @@ import 'basic_types.dart'; ...@@ -8,6 +8,7 @@ import 'basic_types.dart';
/// An immutable style in which paint text. /// An immutable style in which paint text.
class TextStyle { class TextStyle {
/// Creates a text style.
const TextStyle({ const TextStyle({
this.inherit: true, this.inherit: true,
this.color, this.color,
...@@ -25,7 +26,7 @@ class TextStyle { ...@@ -25,7 +26,7 @@ class TextStyle {
this.decorationStyle this.decorationStyle
}); });
/// Whether null values are replaced with their value in an ancestor text style. /// Whether null values are replaced with their value in an ancestor text style (e.g., in a [TextSpan] tree).
final bool inherit; final bool inherit;
/// The color to use when painting the text. /// The color to use when painting the text.
...@@ -154,7 +155,7 @@ class TextStyle { ...@@ -154,7 +155,7 @@ class TextStyle {
); );
} }
/// The style information for text runs, encoded for use by `dart:ui`.
ui.TextStyle get textStyle { ui.TextStyle get textStyle {
return new ui.TextStyle( return new ui.TextStyle(
color: color, color: color,
...@@ -171,6 +172,7 @@ class TextStyle { ...@@ -171,6 +172,7 @@ class TextStyle {
); );
} }
/// The style information for paragraphs, encoded for use by `dart:ui`.
ui.ParagraphStyle get paragraphStyle { ui.ParagraphStyle get paragraphStyle {
return new ui.ParagraphStyle( return new ui.ParagraphStyle(
textAlign: textAlign, textAlign: textAlign,
......
...@@ -1720,13 +1720,33 @@ class Flexible extends ParentDataWidget<Flex> { ...@@ -1720,13 +1720,33 @@ class Flexible extends ParentDataWidget<Flex> {
/// A paragraph of rich text. /// A paragraph of rich text.
/// ///
/// Consider using [Text], which integrates with [DefaultTextStyle], rather than /// The [RichText] widget displays text using a variety of different styles. The
/// this widget, which requires explicit styling. /// text to display is described using a tree of [TextSpan] objects, each of
/// which has an associated style, which is used for that subtree. The text
/// might break across multiple lines or might all be displayed on the layout
/// constraints.
///
/// Text displayed in a [RichText] widget must be explicitly styled. When
/// picking which style to use, consider using the closest enclosing
/// [DefaultTextStyle] to provide defaults.
///
/// All the text uses the same style, consider using the [Text] widget, which is
/// less verbose and integrates with [DefaultTextStyle] for default styling.
///
/// See also:
///
/// * [Text]
/// * [TextSpan]
/// * [DefaultTextStyle]
class RichText extends LeafRenderObjectWidget { class RichText extends LeafRenderObjectWidget {
/// Creates a paragraph of rich text.
///
/// The [text] argument is required to be non-null.
RichText({ Key key, this.text }) : super(key: key) { RichText({ Key key, this.text }) : super(key: key) {
assert(text != null); assert(text != null);
} }
/// The text to display in this widget.
final TextSpan text; final TextSpan text;
@override @override
...@@ -1768,11 +1788,31 @@ class DefaultTextStyle extends InheritedWidget { ...@@ -1768,11 +1788,31 @@ class DefaultTextStyle extends InheritedWidget {
} }
} }
/// A run of text. /// A run of text with a single style.
///
/// The [Text] widget displays a string of text with single style. The string
/// might break across multiple lines or might all be displayed on the layout
/// constraints.
/// ///
/// By default, the text will be styled using the closest enclosing /// The [style] argument is optional. When omitted, the text will use the style
/// [DefaultTextStyle]. /// from the closest enclosing [DefaultTextStyle] by default. If the given
/// style's [TextStyle.inherit] property is true, the given style will be
/// merged with the closest enclosing [DefaultTextStyle]. This merging behavior
/// is useful, for example, to make the text bold while using the default font
/// family and size.
///
/// To display text that uses multiple styles (e.g., a paragraph with some bold
/// words), use [RichText].
///
/// See also:
///
/// * [RichText]
/// * [DefaultTextStyle]
class Text extends StatelessWidget { class Text extends StatelessWidget {
/// Creates a text widget.
///
/// If the [style] argument is null, the text will use the style from the
/// closest enclosing [DefaultTextStyle].
Text(this.data, { Key key, this.style }) : super(key: key) { Text(this.data, { Key key, this.style }) : super(key: key) {
assert(data != null); assert(data != null);
} }
...@@ -1818,6 +1858,11 @@ class Text extends StatelessWidget { ...@@ -1818,6 +1858,11 @@ class Text extends StatelessWidget {
/// This widget is rarely used directly. Instead, consider using [AssetImage] or /// This widget is rarely used directly. Instead, consider using [AssetImage] or
/// [NetworkImage], depending on whather you wish to display an image from the /// [NetworkImage], depending on whather you wish to display an image from the
/// assert bundle or from the network. /// assert bundle or from the network.
///
/// See also:
///
/// * [AssetImage]
/// * [NetworkImage]
class RawImage extends LeafRenderObjectWidget { class RawImage extends LeafRenderObjectWidget {
RawImage({ RawImage({
Key key, Key key,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment