| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // 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 show TextHeightBehavior; |
| |
| import 'package:flutter/rendering.dart'; |
| |
| import 'basic.dart'; |
| import 'default_selection_style.dart'; |
| import 'framework.dart'; |
| import 'inherited_theme.dart'; |
| import 'media_query.dart'; |
| import 'selection_container.dart'; |
| |
| // Examples can assume: |
| // late String _name; |
| // late BuildContext context; |
| |
| /// The text style to apply to descendant [Text] widgets which don't have an |
| /// explicit style. |
| /// |
| /// See also: |
| /// |
| /// * [AnimatedDefaultTextStyle], which animates changes in the text style |
| /// smoothly over a given duration. |
| /// * [DefaultTextStyleTransition], which takes a provided [Animation] to |
| /// animate changes in text style smoothly over time. |
| class DefaultTextStyle extends InheritedTheme { |
| /// Creates a default text style for the given subtree. |
| /// |
| /// Consider using [DefaultTextStyle.merge] to inherit styling information |
| /// from the current default text style for a given [BuildContext]. |
| /// |
| /// The [style] and [child] arguments are required and must not be null. |
| /// |
| /// The [softWrap] and [overflow] arguments must not be null (though they do |
| /// have default values). |
| /// |
| /// The [maxLines] property may be null (and indeed defaults to null), but if |
| /// it is not null, it must be greater than zero. |
| const DefaultTextStyle({ |
| super.key, |
| required this.style, |
| this.textAlign, |
| this.softWrap = true, |
| this.overflow = TextOverflow.clip, |
| this.maxLines, |
| this.textWidthBasis = TextWidthBasis.parent, |
| this.textHeightBehavior, |
| required super.child, |
| }) : assert(style != null), |
| assert(softWrap != null), |
| assert(overflow != null), |
| assert(maxLines == null || maxLines > 0), |
| assert(child != null), |
| assert(textWidthBasis != null); |
| |
| /// A const-constructable default text style that provides fallback values. |
| /// |
| /// Returned from [of] when the given [BuildContext] doesn't have an enclosing default text style. |
| /// |
| /// This constructor creates a [DefaultTextStyle] with an invalid [child], which |
| /// means the constructed value cannot be incorporated into the tree. |
| const DefaultTextStyle.fallback({ super.key }) |
| : style = const TextStyle(), |
| textAlign = null, |
| softWrap = true, |
| maxLines = null, |
| overflow = TextOverflow.clip, |
| textWidthBasis = TextWidthBasis.parent, |
| textHeightBehavior = null, |
| super(child: const _NullWidget()); |
| |
| /// Creates a default text style that overrides the text styles in scope at |
| /// this point in the widget tree. |
| /// |
| /// The given [style] is merged with the [style] from the default text style |
| /// for the [BuildContext] where the widget is inserted, and any of the other |
| /// arguments that are not null replace the corresponding properties on that |
| /// same default text style. |
| /// |
| /// This constructor cannot be used to override the [maxLines] property of the |
| /// ancestor with the value null, since null here is used to mean "defer to |
| /// ancestor". To replace a non-null [maxLines] from an ancestor with the null |
| /// value (to remove the restriction on number of lines), manually obtain the |
| /// ambient [DefaultTextStyle] using [DefaultTextStyle.of], then create a new |
| /// [DefaultTextStyle] using the [DefaultTextStyle.new] constructor directly. |
| /// See the source below for an example of how to do this (since that's |
| /// essentially what this constructor does). |
| static Widget merge({ |
| Key? key, |
| TextStyle? style, |
| TextAlign? textAlign, |
| bool? softWrap, |
| TextOverflow? overflow, |
| int? maxLines, |
| TextWidthBasis? textWidthBasis, |
| required Widget child, |
| }) { |
| assert(child != null); |
| return Builder( |
| builder: (BuildContext context) { |
| final DefaultTextStyle parent = DefaultTextStyle.of(context); |
| return DefaultTextStyle( |
| key: key, |
| style: parent.style.merge(style), |
| textAlign: textAlign ?? parent.textAlign, |
| softWrap: softWrap ?? parent.softWrap, |
| overflow: overflow ?? parent.overflow, |
| maxLines: maxLines ?? parent.maxLines, |
| textWidthBasis: textWidthBasis ?? parent.textWidthBasis, |
| child: child, |
| ); |
| }, |
| ); |
| } |
| |
| /// The text style to apply. |
| final TextStyle style; |
| |
| /// How each line of text in the Text widget 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. |
| /// |
| /// This also decides the [overflow] property's behavior. If this is true or null, |
| /// the glyph causing overflow, and those that follow, will not be rendered. |
| final bool softWrap; |
| |
| /// How visual overflow should be handled. |
| /// |
| /// If [softWrap] is true or null, the glyph causing overflow, and those that follow, |
| /// will not be rendered. Otherwise, it will be shown with the given overflow option. |
| 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]. |
| /// |
| /// If this is 1, text will not wrap. Otherwise, text will be wrapped at the |
| /// edge of the box. |
| /// |
| /// If this is non-null, it will override even explicit null values of |
| /// [Text.maxLines]. |
| final int? maxLines; |
| |
| /// The strategy to use when calculating the width of the Text. |
| /// |
| /// See [TextWidthBasis] for possible values and their implications. |
| final TextWidthBasis textWidthBasis; |
| |
| /// {@macro dart.ui.textHeightBehavior} |
| final ui.TextHeightBehavior? textHeightBehavior; |
| |
| /// The closest instance of this class that encloses the given context. |
| /// |
| /// If no such instance exists, returns an instance created by |
| /// [DefaultTextStyle.fallback], which contains fallback values. |
| /// |
| /// Typical usage is as follows: |
| /// |
| /// ```dart |
| /// DefaultTextStyle style = DefaultTextStyle.of(context); |
| /// ``` |
| static DefaultTextStyle of(BuildContext context) { |
| return context.dependOnInheritedWidgetOfExactType<DefaultTextStyle>() ?? const DefaultTextStyle.fallback(); |
| } |
| |
| @override |
| bool updateShouldNotify(DefaultTextStyle oldWidget) { |
| return style != oldWidget.style || |
| textAlign != oldWidget.textAlign || |
| softWrap != oldWidget.softWrap || |
| overflow != oldWidget.overflow || |
| maxLines != oldWidget.maxLines || |
| textWidthBasis != oldWidget.textWidthBasis || |
| textHeightBehavior != oldWidget.textHeightBehavior; |
| } |
| |
| @override |
| Widget wrap(BuildContext context, Widget child) { |
| return DefaultTextStyle( |
| style: style, |
| textAlign: textAlign, |
| softWrap: softWrap, |
| overflow: overflow, |
| maxLines: maxLines, |
| textWidthBasis: textWidthBasis, |
| textHeightBehavior: textHeightBehavior, |
| child: child, |
| ); |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| style.debugFillProperties(properties); |
| properties.add(EnumProperty<TextAlign>('textAlign', textAlign, defaultValue: null)); |
| properties.add(FlagProperty('softWrap', value: softWrap, ifTrue: 'wrapping at box width', ifFalse: 'no wrapping except at line break characters', showName: true)); |
| properties.add(EnumProperty<TextOverflow>('overflow', overflow, defaultValue: null)); |
| properties.add(IntProperty('maxLines', maxLines, defaultValue: null)); |
| properties.add(EnumProperty<TextWidthBasis>('textWidthBasis', textWidthBasis, defaultValue: TextWidthBasis.parent)); |
| properties.add(DiagnosticsProperty<ui.TextHeightBehavior>('textHeightBehavior', textHeightBehavior, defaultValue: null)); |
| } |
| } |
| |
| class _NullWidget extends StatelessWidget { |
| const _NullWidget(); |
| |
| @override |
| Widget build(BuildContext context) { |
| throw FlutterError( |
| 'A DefaultTextStyle constructed with DefaultTextStyle.fallback cannot be incorporated into the widget tree, ' |
| 'it is meant only to provide a fallback value returned by DefaultTextStyle.of() ' |
| 'when no enclosing default text style is present in a BuildContext.', |
| ); |
| } |
| } |
| |
| /// The [TextHeightBehavior] that will apply to descendant [Text] and [EditableText] |
| /// widgets which have not explicitly set [Text.textHeightBehavior]. |
| /// |
| /// If there is a [DefaultTextStyle] with a non-null [DefaultTextStyle.textHeightBehavior] |
| /// below this widget, the [DefaultTextStyle.textHeightBehavior] will be used |
| /// over this widget's [TextHeightBehavior]. |
| /// |
| /// See also: |
| /// |
| /// * [DefaultTextStyle], which defines a [TextStyle] to apply to descendant |
| /// [Text] widgets. |
| class DefaultTextHeightBehavior extends InheritedTheme { |
| /// Creates a default text height behavior for the given subtree. |
| /// |
| /// The [textHeightBehavior] and [child] arguments are required and must not be null. |
| const DefaultTextHeightBehavior({ |
| super.key, |
| required this.textHeightBehavior, |
| required super.child, |
| }) : assert(textHeightBehavior != null), |
| assert(child != null); |
| |
| /// {@macro dart.ui.textHeightBehavior} |
| final TextHeightBehavior textHeightBehavior; |
| |
| /// The closest instance of this class that encloses the given context. |
| /// |
| /// If no such instance exists, this method will return `null`. |
| /// |
| /// Typical usage is as follows: |
| /// |
| /// ```dart |
| /// TextHeightBehavior defaultTextHeightBehavior = DefaultTextHeightBehavior.of(context)!; |
| /// ``` |
| static TextHeightBehavior? of(BuildContext context) { |
| return context.dependOnInheritedWidgetOfExactType<DefaultTextHeightBehavior>()?.textHeightBehavior; |
| } |
| |
| @override |
| bool updateShouldNotify(DefaultTextHeightBehavior oldWidget) { |
| return textHeightBehavior != oldWidget.textHeightBehavior; |
| } |
| |
| @override |
| Widget wrap(BuildContext context, Widget child) { |
| return DefaultTextHeightBehavior( |
| textHeightBehavior: textHeightBehavior, |
| child: child, |
| ); |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DiagnosticsProperty<ui.TextHeightBehavior>('textHeightBehavior', textHeightBehavior, defaultValue: null)); |
| } |
| } |
| |
| /// 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 same line |
| /// depending on the layout constraints. |
| /// |
| /// The [style] argument is optional. When omitted, the text will use the style |
| /// from the closest enclosing [DefaultTextStyle]. If the given style's |
| /// [TextStyle.inherit] property is true (the default), 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. |
| /// |
| /// {@tool snippet} |
| /// |
| /// This example shows how to display text using the [Text] widget with the |
| /// [overflow] set to [TextOverflow.ellipsis]. |
| /// |
| /// ![If the text is shorter than the available space, it is displayed in full without an ellipsis.](https://flutter.github.io/assets-for-api-docs/assets/widgets/text.png) |
| /// |
| /// ![If the text overflows, the Text widget displays an ellipsis to trim the overflowing text](https://flutter.github.io/assets-for-api-docs/assets/widgets/text_ellipsis.png) |
| /// |
| /// ```dart |
| /// Text( |
| /// 'Hello, $_name! How are you?', |
| /// textAlign: TextAlign.center, |
| /// overflow: TextOverflow.ellipsis, |
| /// style: const TextStyle(fontWeight: FontWeight.bold), |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// Using the [Text.rich] constructor, the [Text] widget can |
| /// display a paragraph with differently styled [TextSpan]s. The sample |
| /// that follows displays "Hello beautiful world" with different styles |
| /// for each word. |
| /// |
| /// {@tool snippet} |
| /// |
| /// ![The word "Hello" is shown with the default text styles. The word "beautiful" is italicized. The word "world" is bold.](https://flutter.github.io/assets-for-api-docs/assets/widgets/text_rich.png) |
| /// |
| /// ```dart |
| /// const Text.rich( |
| /// TextSpan( |
| /// text: 'Hello', // default text style |
| /// children: <TextSpan>[ |
| /// TextSpan(text: ' beautiful ', style: TextStyle(fontStyle: FontStyle.italic)), |
| /// TextSpan(text: 'world', style: TextStyle(fontWeight: FontWeight.bold)), |
| /// ], |
| /// ), |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// ## Interactivity |
| /// |
| /// To make [Text] react to touch events, wrap it in a [GestureDetector] widget |
| /// with a [GestureDetector.onTap] handler. |
| /// |
| /// In a Material Design application, consider using a [TextButton] instead, or |
| /// if that isn't appropriate, at least using an [InkWell] instead of |
| /// [GestureDetector]. |
| /// |
| /// To make sections of the text interactive, use [RichText] and specify a |
| /// [TapGestureRecognizer] as the [TextSpan.recognizer] of the relevant part of |
| /// the text. |
| /// |
| /// ## Selection |
| /// |
| /// [Text] is not selectable by default. To make a [Text] selectable, one can |
| /// wrap a subtree with a [SelectionArea] widget. To exclude a part of a subtree |
| /// under [SelectionArea] from selection, once can also wrap that part of the |
| /// subtree with [SelectionContainer.disabled]. |
| /// |
| /// {@tool dartpad} |
| /// This sample demonstrates how to disable selection for a Text under a |
| /// SelectionArea. |
| /// |
| /// ** See code in examples/api/lib/material/selection_container/selection_container_disabled.0.dart ** |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [RichText], which gives you more control over the text styles. |
| /// * [DefaultTextStyle], which sets default styles for [Text] widgets. |
| /// * [SelectableRegion], which provides an overview of the selection system. |
| 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]. |
| /// |
| /// The [data] parameter must not be null. |
| /// |
| /// The [overflow] property's behavior is affected by the [softWrap] argument. |
| /// If the [softWrap] is true or null, the glyph causing overflow, and those |
| /// that follow, will not be rendered. Otherwise, it will be shown with the |
| /// given overflow option. |
| const Text( |
| String this.data, { |
| super.key, |
| this.style, |
| this.strutStyle, |
| this.textAlign, |
| this.textDirection, |
| this.locale, |
| this.softWrap, |
| this.overflow, |
| this.textScaleFactor, |
| this.maxLines, |
| this.semanticsLabel, |
| this.textWidthBasis, |
| this.textHeightBehavior, |
| this.selectionColor, |
| }) : assert( |
| data != null, |
| 'A non-null String must be provided to a Text widget.', |
| ), |
| textSpan = null; |
| |
| /// Creates a text widget with a [InlineSpan]. |
| /// |
| /// The following subclasses of [InlineSpan] may be used to build rich text: |
| /// |
| /// * [TextSpan]s define text and children [InlineSpan]s. |
| /// * [WidgetSpan]s define embedded inline widgets. |
| /// |
| /// The [textSpan] parameter must not be null. |
| /// |
| /// See [RichText] which provides a lower-level way to draw text. |
| const Text.rich( |
| InlineSpan this.textSpan, { |
| super.key, |
| this.style, |
| this.strutStyle, |
| this.textAlign, |
| this.textDirection, |
| this.locale, |
| this.softWrap, |
| this.overflow, |
| this.textScaleFactor, |
| this.maxLines, |
| this.semanticsLabel, |
| this.textWidthBasis, |
| this.textHeightBehavior, |
| this.selectionColor, |
| }) : assert( |
| textSpan != null, |
| 'A non-null TextSpan must be provided to a Text.rich widget.', |
| ), |
| data = null; |
| |
| /// The text to display. |
| /// |
| /// This will be null if a [textSpan] is provided instead. |
| final String? data; |
| |
| /// The text to display as a [InlineSpan]. |
| /// |
| /// This will be null if [data] is provided instead. |
| final InlineSpan? textSpan; |
| |
| /// If non-null, the style to use for this text. |
| /// |
| /// If the style's "inherit" property is true, the style will be merged with |
| /// the closest enclosing [DefaultTextStyle]. Otherwise, the style will |
| /// replace the closest enclosing [DefaultTextStyle]. |
| final TextStyle? style; |
| |
| /// {@macro flutter.painting.textPainter.strutStyle} |
| final StrutStyle? strutStyle; |
| |
| /// How the text should be aligned horizontally. |
| final TextAlign? textAlign; |
| |
| /// The directionality of the text. |
| /// |
| /// This decides how [textAlign] values like [TextAlign.start] and |
| /// [TextAlign.end] are interpreted. |
| /// |
| /// This is also used to disambiguate how to render bidirectional text. For |
| /// example, if the [data] is an English phrase followed by a Hebrew phrase, |
| /// in a [TextDirection.ltr] context the English phrase will be on the left |
| /// and the Hebrew phrase to its right, while in a [TextDirection.rtl] |
| /// context, the English phrase will be on the right and the Hebrew phrase on |
| /// its left. |
| /// |
| /// Defaults to the ambient [Directionality], if any. |
| final TextDirection? textDirection; |
| |
| /// Used to select a font when the same Unicode character can |
| /// be rendered differently, depending on the locale. |
| /// |
| /// It's rarely necessary to set this property. By default its value |
| /// is inherited from the enclosing app with `Localizations.localeOf(context)`. |
| /// |
| /// See [RenderParagraph.locale] for more information. |
| final Locale? locale; |
| |
| /// 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. |
| /// |
| /// If this is null [TextStyle.overflow] will be used, otherwise the value |
| /// from the nearest [DefaultTextStyle] ancestor will be used. |
| final TextOverflow? overflow; |
| |
| /// The number of font pixels for each logical pixel. |
| /// |
| /// For example, if the text scale factor is 1.5, text will be 50% larger than |
| /// the specified font size. |
| /// |
| /// The value given to the constructor as textScaleFactor. If null, will |
| /// use the [MediaQueryData.textScaleFactor] obtained from the ambient |
| /// [MediaQuery], or 1.0 if there is no [MediaQuery] in scope. |
| 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]. |
| /// |
| /// If this is 1, text will not wrap. Otherwise, text will be wrapped at the |
| /// edge of the box. |
| /// |
| /// If this is null, but there is an ambient [DefaultTextStyle] that specifies |
| /// an explicit number for its [DefaultTextStyle.maxLines], then the |
| /// [DefaultTextStyle] value will take precedence. You can use a [RichText] |
| /// widget directly to entirely override the [DefaultTextStyle]. |
| final int? maxLines; |
| |
| /// {@template flutter.widgets.Text.semanticsLabel} |
| /// An alternative semantics label for this text. |
| /// |
| /// If present, the semantics of this widget will contain this value instead |
| /// of the actual text. This will overwrite any of the semantics labels applied |
| /// directly to the [TextSpan]s. |
| /// |
| /// This is useful for replacing abbreviations or shorthands with the full |
| /// text value: |
| /// |
| /// ```dart |
| /// const Text(r'$$', semanticsLabel: 'Double dollars') |
| /// ``` |
| /// {@endtemplate} |
| final String? semanticsLabel; |
| |
| /// {@macro flutter.painting.textPainter.textWidthBasis} |
| final TextWidthBasis? textWidthBasis; |
| |
| /// {@macro dart.ui.textHeightBehavior} |
| final ui.TextHeightBehavior? textHeightBehavior; |
| |
| /// The color to use when painting the selection. |
| /// |
| /// This is ignored if [SelectionContainer.maybeOf] returns null |
| /// in the [BuildContext] of the [Text] widget. |
| /// |
| /// If null, the ambient [DefaultSelectionStyle] is used (if any); failing |
| /// that, the selection color defaults to [DefaultSelectionStyle.defaultColor] |
| /// (semi-transparent grey). |
| final Color? selectionColor; |
| |
| @override |
| Widget build(BuildContext context) { |
| final DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context); |
| TextStyle? effectiveTextStyle = style; |
| if (style == null || style!.inherit) { |
| effectiveTextStyle = defaultTextStyle.style.merge(style); |
| } |
| if (MediaQuery.boldTextOverride(context)) { |
| effectiveTextStyle = effectiveTextStyle!.merge(const TextStyle(fontWeight: FontWeight.bold)); |
| } |
| final SelectionRegistrar? registrar = SelectionContainer.maybeOf(context); |
| Widget result = RichText( |
| textAlign: textAlign ?? defaultTextStyle.textAlign ?? TextAlign.start, |
| 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 |
| softWrap: softWrap ?? defaultTextStyle.softWrap, |
| overflow: overflow ?? effectiveTextStyle?.overflow ?? defaultTextStyle.overflow, |
| textScaleFactor: textScaleFactor ?? MediaQuery.textScaleFactorOf(context), |
| maxLines: maxLines ?? defaultTextStyle.maxLines, |
| strutStyle: strutStyle, |
| textWidthBasis: textWidthBasis ?? defaultTextStyle.textWidthBasis, |
| textHeightBehavior: textHeightBehavior ?? defaultTextStyle.textHeightBehavior ?? DefaultTextHeightBehavior.of(context), |
| selectionRegistrar: registrar, |
| selectionColor: selectionColor ?? DefaultSelectionStyle.of(context).selectionColor ?? DefaultSelectionStyle.defaultColor, |
| text: TextSpan( |
| style: effectiveTextStyle, |
| text: data, |
| children: textSpan != null ? <InlineSpan>[textSpan!] : null, |
| ), |
| ); |
| if (registrar != null) { |
| result = MouseRegion( |
| cursor: SystemMouseCursors.text, |
| child: result, |
| ); |
| } |
| if (semanticsLabel != null) { |
| result = Semantics( |
| textDirection: textDirection, |
| label: semanticsLabel, |
| child: ExcludeSemantics( |
| child: result, |
| ), |
| ); |
| } |
| return result; |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(StringProperty('data', data, showName: false)); |
| if (textSpan != null) { |
| properties.add(textSpan!.toDiagnosticsNode(name: 'textSpan', style: DiagnosticsTreeStyle.transition)); |
| } |
| style?.debugFillProperties(properties); |
| properties.add(EnumProperty<TextAlign>('textAlign', textAlign, defaultValue: null)); |
| properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null)); |
| properties.add(DiagnosticsProperty<Locale>('locale', locale, defaultValue: null)); |
| properties.add(FlagProperty('softWrap', value: softWrap, ifTrue: 'wrapping at box width', ifFalse: 'no wrapping except at line break characters', showName: true)); |
| properties.add(EnumProperty<TextOverflow>('overflow', overflow, defaultValue: null)); |
| properties.add(DoubleProperty('textScaleFactor', textScaleFactor, defaultValue: null)); |
| properties.add(IntProperty('maxLines', maxLines, defaultValue: null)); |
| properties.add(EnumProperty<TextWidthBasis>('textWidthBasis', textWidthBasis, defaultValue: null)); |
| properties.add(DiagnosticsProperty<ui.TextHeightBehavior>('textHeightBehavior', textHeightBehavior, defaultValue: null)); |
| if (semanticsLabel != null) { |
| properties.add(StringProperty('semanticsLabel', semanticsLabel)); |
| } |
| } |
| } |