mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
SliverSemantics (#167300)
Fixes #166785 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. --------- Co-authored-by: Renzo Olivares <roliv@google.com>
This commit is contained in:
parent
4f72a04a5e
commit
220477fc2c
@ -154,7 +154,8 @@ class _SliverEnsureSemanticsExampleState extends State<SliverEnsureSemanticsExam
|
||||
),
|
||||
),
|
||||
SliverEnsureSemantics(
|
||||
sliver: SliverSemanticsList(
|
||||
sliver: SliverSemantics(
|
||||
role: SemanticsRole.list,
|
||||
sliver: SliverFixedExtentList(
|
||||
itemExtent: 44.0,
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
@ -189,19 +190,3 @@ class _SliverEnsureSemanticsExampleState extends State<SliverEnsureSemanticsExam
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// A sliver that assigns the role of SemanticsRole.list to its sliver child.
|
||||
class SliverSemanticsList extends SingleChildRenderObjectWidget {
|
||||
const SliverSemanticsList({super.key, required Widget sliver}) : super(child: sliver);
|
||||
|
||||
@override
|
||||
RenderSliverSemanticsList createRenderObject(BuildContext context) => RenderSliverSemanticsList();
|
||||
}
|
||||
|
||||
class RenderSliverSemanticsList extends RenderProxySliver {
|
||||
@override
|
||||
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
||||
super.describeSemanticsConfiguration(config);
|
||||
config.role = SemanticsRole.list;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4595,6 +4595,493 @@ mixin RelayoutWhenSystemFontsChangeMixin on RenderObject {
|
||||
}
|
||||
}
|
||||
|
||||
/// A mixin for [RenderObject]s that want to annotate the [SemanticsNode]
|
||||
/// for their subtree.
|
||||
mixin SemanticsAnnotationsMixin on RenderObject {
|
||||
/// Initializes the semantics annotations for this mixin.
|
||||
// Parameters added to this method should be marked as required to ensure
|
||||
// callers of the method provide a value.
|
||||
void initSemanticsAnnotations({
|
||||
required SemanticsProperties properties,
|
||||
required bool container,
|
||||
required bool explicitChildNodes,
|
||||
required bool excludeSemantics,
|
||||
required bool blockUserActions,
|
||||
required Locale? localeForSubtree,
|
||||
required TextDirection? textDirection,
|
||||
}) {
|
||||
_properties = properties;
|
||||
_container = container;
|
||||
_explicitChildNodes = explicitChildNodes;
|
||||
_excludeSemantics = excludeSemantics;
|
||||
_blockUserActions = blockUserActions;
|
||||
_localeForSubtree = localeForSubtree;
|
||||
_textDirection = textDirection;
|
||||
_updateAttributedFields(_properties);
|
||||
}
|
||||
|
||||
/// All of the [SemanticsProperties] for this [SemanticsAnnotationsMixin].
|
||||
SemanticsProperties get properties => _properties;
|
||||
late SemanticsProperties _properties;
|
||||
set properties(SemanticsProperties value) {
|
||||
if (_properties == value) {
|
||||
return;
|
||||
}
|
||||
_properties = value;
|
||||
_updateAttributedFields(_properties);
|
||||
markNeedsSemanticsUpdate();
|
||||
}
|
||||
|
||||
/// If 'container' is true, this [RenderObject] will introduce a new
|
||||
/// node in the semantics tree. Otherwise, the semantics will be
|
||||
/// merged with the semantics of any ancestors.
|
||||
///
|
||||
/// Whether descendants of this [RenderObject] can add their semantic information
|
||||
/// to the [SemanticsNode] introduced by this configuration is controlled by
|
||||
/// [explicitChildNodes].
|
||||
bool get container => _container;
|
||||
late bool _container;
|
||||
set container(bool value) {
|
||||
if (container == value) {
|
||||
return;
|
||||
}
|
||||
_container = value;
|
||||
markNeedsSemanticsUpdate();
|
||||
}
|
||||
|
||||
/// Whether descendants of this [RenderObject] are allowed to add semantic
|
||||
/// information to the [SemanticsNode] annotated by this widget.
|
||||
///
|
||||
/// When set to false descendants are allowed to annotate [SemanticsNode]s of
|
||||
/// their parent with the semantic information they want to contribute to the
|
||||
/// semantic tree.
|
||||
/// When set to true the only way for descendants to contribute semantic
|
||||
/// information to the semantic tree is to introduce new explicit
|
||||
/// [SemanticsNode]s to the tree.
|
||||
///
|
||||
/// This setting is often used in combination with
|
||||
/// [SemanticsConfiguration.isSemanticBoundary] to create semantic boundaries
|
||||
/// that are either writable or not for children.
|
||||
bool get explicitChildNodes => _explicitChildNodes;
|
||||
late bool _explicitChildNodes;
|
||||
set explicitChildNodes(bool value) {
|
||||
if (_explicitChildNodes == value) {
|
||||
return;
|
||||
}
|
||||
_explicitChildNodes = value;
|
||||
markNeedsSemanticsUpdate();
|
||||
}
|
||||
|
||||
/// Whether descendants of this [RenderObject] should have their semantic
|
||||
/// information ignored.
|
||||
///
|
||||
/// When this flag is set to true, all child semantics nodes are ignored.
|
||||
/// This can be used as a convenience for cases where a child is wrapped in
|
||||
/// an [ExcludeSemantics] widget and then another [Semantics] widget.
|
||||
bool get excludeSemantics => _excludeSemantics;
|
||||
late bool _excludeSemantics;
|
||||
set excludeSemantics(bool value) {
|
||||
if (_excludeSemantics == value) {
|
||||
return;
|
||||
}
|
||||
_excludeSemantics = value;
|
||||
markNeedsSemanticsUpdate();
|
||||
}
|
||||
|
||||
/// Whether to block user interactions for the semantics subtree.
|
||||
///
|
||||
/// Setting this true prevents user from activating pointer related
|
||||
/// [SemanticsAction]s, such as [SemanticsAction.tap] or
|
||||
/// [SemanticsAction.longPress].
|
||||
bool get blockUserActions => _blockUserActions;
|
||||
late bool _blockUserActions;
|
||||
set blockUserActions(bool value) {
|
||||
if (_blockUserActions == value) {
|
||||
return;
|
||||
}
|
||||
_blockUserActions = value;
|
||||
markNeedsSemanticsUpdate();
|
||||
}
|
||||
|
||||
/// The [Locale] for the semantics subtree.
|
||||
///
|
||||
/// Setting this to null will inherit locale from ancestor semantics node.
|
||||
Locale? get localeForSubtree => _localeForSubtree;
|
||||
Locale? _localeForSubtree;
|
||||
set localeForSubtree(Locale? value) {
|
||||
if (_localeForSubtree == value) {
|
||||
return;
|
||||
}
|
||||
_localeForSubtree = value;
|
||||
markNeedsSemanticsUpdate();
|
||||
}
|
||||
|
||||
void _updateAttributedFields(SemanticsProperties value) {
|
||||
_attributedLabel = _effectiveAttributedLabel(value);
|
||||
_attributedValue = _effectiveAttributedValue(value);
|
||||
_attributedIncreasedValue = _effectiveAttributedIncreasedValue(value);
|
||||
_attributedDecreasedValue = _effectiveAttributedDecreasedValue(value);
|
||||
_attributedHint = _effectiveAttributedHint(value);
|
||||
}
|
||||
|
||||
AttributedString? _effectiveAttributedLabel(SemanticsProperties value) {
|
||||
return value.attributedLabel ?? (value.label == null ? null : AttributedString(value.label!));
|
||||
}
|
||||
|
||||
AttributedString? _effectiveAttributedValue(SemanticsProperties value) {
|
||||
return value.attributedValue ?? (value.value == null ? null : AttributedString(value.value!));
|
||||
}
|
||||
|
||||
AttributedString? _effectiveAttributedIncreasedValue(SemanticsProperties value) {
|
||||
return value.attributedIncreasedValue ??
|
||||
(value.increasedValue == null ? null : AttributedString(value.increasedValue!));
|
||||
}
|
||||
|
||||
AttributedString? _effectiveAttributedDecreasedValue(SemanticsProperties value) {
|
||||
return properties.attributedDecreasedValue ??
|
||||
(value.decreasedValue == null ? null : AttributedString(value.decreasedValue!));
|
||||
}
|
||||
|
||||
AttributedString? _effectiveAttributedHint(SemanticsProperties value) {
|
||||
return value.attributedHint ?? (value.hint == null ? null : AttributedString(value.hint!));
|
||||
}
|
||||
|
||||
AttributedString? _attributedLabel;
|
||||
AttributedString? _attributedValue;
|
||||
AttributedString? _attributedIncreasedValue;
|
||||
AttributedString? _attributedDecreasedValue;
|
||||
AttributedString? _attributedHint;
|
||||
|
||||
/// If non-null, sets the [SemanticsNode.textDirection] semantic to the given
|
||||
/// value.
|
||||
///
|
||||
/// This must not be null if [SemanticsProperties.attributedLabel],
|
||||
/// [SemanticsProperties.attributedHint],
|
||||
/// [SemanticsProperties.attributedValue],
|
||||
/// [SemanticsProperties.attributedIncreasedValue], or
|
||||
/// [SemanticsProperties.attributedDecreasedValue] are not null.
|
||||
TextDirection? get textDirection => _textDirection;
|
||||
TextDirection? _textDirection;
|
||||
set textDirection(TextDirection? value) {
|
||||
if (textDirection == value) {
|
||||
return;
|
||||
}
|
||||
_textDirection = value;
|
||||
markNeedsSemanticsUpdate();
|
||||
}
|
||||
|
||||
@override
|
||||
void visitChildrenForSemantics(RenderObjectVisitor visitor) {
|
||||
if (excludeSemantics) {
|
||||
return;
|
||||
}
|
||||
super.visitChildrenForSemantics(visitor);
|
||||
}
|
||||
|
||||
@override
|
||||
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
||||
super.describeSemanticsConfiguration(config);
|
||||
config.isSemanticBoundary = container;
|
||||
config.explicitChildNodes = explicitChildNodes;
|
||||
config.isBlockingUserActions = blockUserActions;
|
||||
config.localeForSubtree = localeForSubtree;
|
||||
assert(
|
||||
((_properties.scopesRoute ?? false) && explicitChildNodes) ||
|
||||
!(_properties.scopesRoute ?? false),
|
||||
'explicitChildNodes must be set to true if scopes route is true',
|
||||
);
|
||||
assert(
|
||||
!((_properties.toggled ?? false) && (_properties.checked ?? false)),
|
||||
'A semantics node cannot be toggled and checked at the same time',
|
||||
);
|
||||
|
||||
if (_properties.enabled != null) {
|
||||
config.isEnabled = _properties.enabled;
|
||||
}
|
||||
if (_properties.checked != null) {
|
||||
config.isChecked = _properties.checked;
|
||||
}
|
||||
if (_properties.mixed != null) {
|
||||
config.isCheckStateMixed = _properties.mixed;
|
||||
}
|
||||
if (_properties.toggled != null) {
|
||||
config.isToggled = _properties.toggled;
|
||||
}
|
||||
if (_properties.selected != null) {
|
||||
config.isSelected = _properties.selected!;
|
||||
}
|
||||
if (_properties.button != null) {
|
||||
config.isButton = _properties.button!;
|
||||
}
|
||||
if (_properties.expanded != null) {
|
||||
config.isExpanded = _properties.expanded;
|
||||
}
|
||||
if (_properties.link != null) {
|
||||
config.isLink = _properties.link!;
|
||||
}
|
||||
if (_properties.linkUrl != null) {
|
||||
config.linkUrl = _properties.linkUrl;
|
||||
}
|
||||
if (_properties.slider != null) {
|
||||
config.isSlider = _properties.slider!;
|
||||
}
|
||||
if (_properties.keyboardKey != null) {
|
||||
config.isKeyboardKey = _properties.keyboardKey!;
|
||||
}
|
||||
if (_properties.header != null) {
|
||||
config.isHeader = _properties.header!;
|
||||
}
|
||||
if (_properties.headingLevel != null) {
|
||||
config.headingLevel = _properties.headingLevel!;
|
||||
}
|
||||
if (_properties.textField != null) {
|
||||
config.isTextField = _properties.textField!;
|
||||
}
|
||||
if (_properties.readOnly != null) {
|
||||
config.isReadOnly = _properties.readOnly!;
|
||||
}
|
||||
if (_properties.focusable != null) {
|
||||
config.isFocusable = _properties.focusable!;
|
||||
}
|
||||
if (_properties.focused != null) {
|
||||
config.isFocused = _properties.focused!;
|
||||
}
|
||||
if (_properties.inMutuallyExclusiveGroup != null) {
|
||||
config.isInMutuallyExclusiveGroup = _properties.inMutuallyExclusiveGroup!;
|
||||
}
|
||||
if (_properties.obscured != null) {
|
||||
config.isObscured = _properties.obscured!;
|
||||
}
|
||||
if (_properties.multiline != null) {
|
||||
config.isMultiline = _properties.multiline!;
|
||||
}
|
||||
if (_properties.hidden != null) {
|
||||
config.isHidden = _properties.hidden!;
|
||||
}
|
||||
if (_properties.image != null) {
|
||||
config.isImage = _properties.image!;
|
||||
}
|
||||
if (_properties.isRequired != null) {
|
||||
config.isRequired = _properties.isRequired;
|
||||
}
|
||||
if (_properties.identifier != null) {
|
||||
config.identifier = _properties.identifier!;
|
||||
}
|
||||
if (_attributedLabel != null) {
|
||||
config.attributedLabel = _attributedLabel!;
|
||||
}
|
||||
if (_attributedValue != null) {
|
||||
config.attributedValue = _attributedValue!;
|
||||
}
|
||||
if (_attributedIncreasedValue != null) {
|
||||
config.attributedIncreasedValue = _attributedIncreasedValue!;
|
||||
}
|
||||
if (_attributedDecreasedValue != null) {
|
||||
config.attributedDecreasedValue = _attributedDecreasedValue!;
|
||||
}
|
||||
if (_attributedHint != null) {
|
||||
config.attributedHint = _attributedHint!;
|
||||
}
|
||||
if (_properties.tooltip != null) {
|
||||
config.tooltip = _properties.tooltip!;
|
||||
}
|
||||
if (_properties.hintOverrides != null && _properties.hintOverrides!.isNotEmpty) {
|
||||
config.hintOverrides = _properties.hintOverrides;
|
||||
}
|
||||
if (_properties.scopesRoute != null) {
|
||||
config.scopesRoute = _properties.scopesRoute!;
|
||||
}
|
||||
if (_properties.namesRoute != null) {
|
||||
config.namesRoute = _properties.namesRoute!;
|
||||
}
|
||||
if (_properties.liveRegion != null) {
|
||||
config.liveRegion = _properties.liveRegion!;
|
||||
}
|
||||
if (_properties.maxValueLength != null) {
|
||||
config.maxValueLength = _properties.maxValueLength;
|
||||
}
|
||||
if (_properties.currentValueLength != null) {
|
||||
config.currentValueLength = _properties.currentValueLength;
|
||||
}
|
||||
if (textDirection != null) {
|
||||
config.textDirection = textDirection;
|
||||
}
|
||||
if (_properties.sortKey != null) {
|
||||
config.sortKey = _properties.sortKey;
|
||||
}
|
||||
if (_properties.tagForChildren != null) {
|
||||
config.addTagForChildren(_properties.tagForChildren!);
|
||||
}
|
||||
if (properties.role != null) {
|
||||
config.role = _properties.role!;
|
||||
}
|
||||
if (_properties.controlsNodes != null) {
|
||||
config.controlsNodes = _properties.controlsNodes;
|
||||
}
|
||||
if (config.validationResult != _properties.validationResult) {
|
||||
config.validationResult = _properties.validationResult;
|
||||
}
|
||||
|
||||
if (_properties.inputType != null) {
|
||||
config.inputType = _properties.inputType!;
|
||||
}
|
||||
|
||||
// Registering _perform* as action handlers instead of the user provided
|
||||
// ones to ensure that changing a user provided handler from a non-null to
|
||||
// another non-null value doesn't require a semantics update.
|
||||
if (_properties.onTap != null) {
|
||||
config.onTap = _performTap;
|
||||
}
|
||||
if (_properties.onLongPress != null) {
|
||||
config.onLongPress = _performLongPress;
|
||||
}
|
||||
if (_properties.onDismiss != null) {
|
||||
config.onDismiss = _performDismiss;
|
||||
}
|
||||
if (_properties.onScrollLeft != null) {
|
||||
config.onScrollLeft = _performScrollLeft;
|
||||
}
|
||||
if (_properties.onScrollRight != null) {
|
||||
config.onScrollRight = _performScrollRight;
|
||||
}
|
||||
if (_properties.onScrollUp != null) {
|
||||
config.onScrollUp = _performScrollUp;
|
||||
}
|
||||
if (_properties.onScrollDown != null) {
|
||||
config.onScrollDown = _performScrollDown;
|
||||
}
|
||||
if (_properties.onIncrease != null) {
|
||||
config.onIncrease = _performIncrease;
|
||||
}
|
||||
if (_properties.onDecrease != null) {
|
||||
config.onDecrease = _performDecrease;
|
||||
}
|
||||
if (_properties.onCopy != null) {
|
||||
config.onCopy = _performCopy;
|
||||
}
|
||||
if (_properties.onCut != null) {
|
||||
config.onCut = _performCut;
|
||||
}
|
||||
if (_properties.onPaste != null) {
|
||||
config.onPaste = _performPaste;
|
||||
}
|
||||
if (_properties.onMoveCursorForwardByCharacter != null) {
|
||||
config.onMoveCursorForwardByCharacter = _performMoveCursorForwardByCharacter;
|
||||
}
|
||||
if (_properties.onMoveCursorBackwardByCharacter != null) {
|
||||
config.onMoveCursorBackwardByCharacter = _performMoveCursorBackwardByCharacter;
|
||||
}
|
||||
if (_properties.onMoveCursorForwardByWord != null) {
|
||||
config.onMoveCursorForwardByWord = _performMoveCursorForwardByWord;
|
||||
}
|
||||
if (_properties.onMoveCursorBackwardByWord != null) {
|
||||
config.onMoveCursorBackwardByWord = _performMoveCursorBackwardByWord;
|
||||
}
|
||||
if (_properties.onSetSelection != null) {
|
||||
config.onSetSelection = _performSetSelection;
|
||||
}
|
||||
if (_properties.onSetText != null) {
|
||||
config.onSetText = _performSetText;
|
||||
}
|
||||
if (_properties.onDidGainAccessibilityFocus != null) {
|
||||
config.onDidGainAccessibilityFocus = _performDidGainAccessibilityFocus;
|
||||
}
|
||||
if (_properties.onDidLoseAccessibilityFocus != null) {
|
||||
config.onDidLoseAccessibilityFocus = _performDidLoseAccessibilityFocus;
|
||||
}
|
||||
if (_properties.onFocus != null) {
|
||||
config.onFocus = _performFocus;
|
||||
}
|
||||
if (_properties.customSemanticsActions != null) {
|
||||
config.customSemanticsActions = _properties.customSemanticsActions!;
|
||||
}
|
||||
}
|
||||
|
||||
void _performTap() {
|
||||
_properties.onTap?.call();
|
||||
}
|
||||
|
||||
void _performLongPress() {
|
||||
_properties.onLongPress?.call();
|
||||
}
|
||||
|
||||
void _performDismiss() {
|
||||
_properties.onDismiss?.call();
|
||||
}
|
||||
|
||||
void _performScrollLeft() {
|
||||
_properties.onScrollLeft?.call();
|
||||
}
|
||||
|
||||
void _performScrollRight() {
|
||||
_properties.onScrollRight?.call();
|
||||
}
|
||||
|
||||
void _performScrollUp() {
|
||||
_properties.onScrollUp?.call();
|
||||
}
|
||||
|
||||
void _performScrollDown() {
|
||||
_properties.onScrollDown?.call();
|
||||
}
|
||||
|
||||
void _performIncrease() {
|
||||
_properties.onIncrease?.call();
|
||||
}
|
||||
|
||||
void _performDecrease() {
|
||||
_properties.onDecrease?.call();
|
||||
}
|
||||
|
||||
void _performCopy() {
|
||||
_properties.onCopy?.call();
|
||||
}
|
||||
|
||||
void _performCut() {
|
||||
_properties.onCut?.call();
|
||||
}
|
||||
|
||||
void _performPaste() {
|
||||
_properties.onPaste?.call();
|
||||
}
|
||||
|
||||
void _performMoveCursorForwardByCharacter(bool extendSelection) {
|
||||
_properties.onMoveCursorForwardByCharacter?.call(extendSelection);
|
||||
}
|
||||
|
||||
void _performMoveCursorBackwardByCharacter(bool extendSelection) {
|
||||
_properties.onMoveCursorBackwardByCharacter?.call(extendSelection);
|
||||
}
|
||||
|
||||
void _performMoveCursorForwardByWord(bool extendSelection) {
|
||||
_properties.onMoveCursorForwardByWord?.call(extendSelection);
|
||||
}
|
||||
|
||||
void _performMoveCursorBackwardByWord(bool extendSelection) {
|
||||
_properties.onMoveCursorBackwardByWord?.call(extendSelection);
|
||||
}
|
||||
|
||||
void _performSetSelection(TextSelection selection) {
|
||||
_properties.onSetSelection?.call(selection);
|
||||
}
|
||||
|
||||
void _performSetText(String text) {
|
||||
_properties.onSetText?.call(text);
|
||||
}
|
||||
|
||||
void _performDidGainAccessibilityFocus() {
|
||||
_properties.onDidGainAccessibilityFocus?.call();
|
||||
}
|
||||
|
||||
void _performDidLoseAccessibilityFocus() {
|
||||
_properties.onDidLoseAccessibilityFocus?.call();
|
||||
}
|
||||
|
||||
void _performFocus() {
|
||||
_properties.onFocus?.call();
|
||||
}
|
||||
}
|
||||
|
||||
/// Properties of _RenderObjectSemantics that are imposed from parent.
|
||||
@immutable
|
||||
final class _SemanticsParentData {
|
||||
|
||||
@ -4231,7 +4231,7 @@ class RenderSemanticsGestureHandler extends RenderProxyBoxWithHitTestBehavior {
|
||||
}
|
||||
|
||||
/// Add annotations to the [SemanticsNode] for this subtree.
|
||||
class RenderSemanticsAnnotations extends RenderProxyBox {
|
||||
class RenderSemanticsAnnotations extends RenderProxyBox with SemanticsAnnotationsMixin {
|
||||
/// Creates a render object that attaches a semantic annotation.
|
||||
///
|
||||
/// If the [SemanticsProperties.attributedLabel] is not null, the [textDirection] must also not be null.
|
||||
@ -4244,476 +4244,16 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
|
||||
bool blockUserActions = false,
|
||||
Locale? localeForSubtree,
|
||||
TextDirection? textDirection,
|
||||
}) : _container = container,
|
||||
_explicitChildNodes = explicitChildNodes,
|
||||
_excludeSemantics = excludeSemantics,
|
||||
_blockUserActions = blockUserActions,
|
||||
_localeForSubtree = localeForSubtree,
|
||||
_textDirection = textDirection,
|
||||
_properties = properties,
|
||||
super(child) {
|
||||
_updateAttributedFields(_properties);
|
||||
}
|
||||
|
||||
/// All of the [SemanticsProperties] for this [RenderSemanticsAnnotations].
|
||||
SemanticsProperties get properties => _properties;
|
||||
SemanticsProperties _properties;
|
||||
set properties(SemanticsProperties value) {
|
||||
if (_properties == value) {
|
||||
return;
|
||||
}
|
||||
_properties = value;
|
||||
_updateAttributedFields(_properties);
|
||||
markNeedsSemanticsUpdate();
|
||||
}
|
||||
|
||||
/// If 'container' is true, this [RenderObject] will introduce a new
|
||||
/// node in the semantics tree. Otherwise, the semantics will be
|
||||
/// merged with the semantics of any ancestors.
|
||||
///
|
||||
/// Whether descendants of this [RenderObject] can add their semantic information
|
||||
/// to the [SemanticsNode] introduced by this configuration is controlled by
|
||||
/// [explicitChildNodes].
|
||||
bool get container => _container;
|
||||
bool _container;
|
||||
set container(bool value) {
|
||||
if (container == value) {
|
||||
return;
|
||||
}
|
||||
_container = value;
|
||||
markNeedsSemanticsUpdate();
|
||||
}
|
||||
|
||||
/// Whether descendants of this [RenderObject] are allowed to add semantic
|
||||
/// information to the [SemanticsNode] annotated by this widget.
|
||||
///
|
||||
/// When set to false descendants are allowed to annotate [SemanticsNode]s of
|
||||
/// their parent with the semantic information they want to contribute to the
|
||||
/// semantic tree.
|
||||
/// When set to true the only way for descendants to contribute semantic
|
||||
/// information to the semantic tree is to introduce new explicit
|
||||
/// [SemanticsNode]s to the tree.
|
||||
///
|
||||
/// This setting is often used in combination with
|
||||
/// [SemanticsConfiguration.isSemanticBoundary] to create semantic boundaries
|
||||
/// that are either writable or not for children.
|
||||
bool get explicitChildNodes => _explicitChildNodes;
|
||||
bool _explicitChildNodes;
|
||||
set explicitChildNodes(bool value) {
|
||||
if (_explicitChildNodes == value) {
|
||||
return;
|
||||
}
|
||||
_explicitChildNodes = value;
|
||||
markNeedsSemanticsUpdate();
|
||||
}
|
||||
|
||||
/// Whether descendants of this [RenderObject] should have their semantic
|
||||
/// information ignored.
|
||||
///
|
||||
/// When this flag is set to true, all child semantics nodes are ignored.
|
||||
/// This can be used as a convenience for cases where a child is wrapped in
|
||||
/// an [ExcludeSemantics] widget and then another [Semantics] widget.
|
||||
bool get excludeSemantics => _excludeSemantics;
|
||||
bool _excludeSemantics;
|
||||
set excludeSemantics(bool value) {
|
||||
if (_excludeSemantics == value) {
|
||||
return;
|
||||
}
|
||||
_excludeSemantics = value;
|
||||
markNeedsSemanticsUpdate();
|
||||
}
|
||||
|
||||
/// Whether to block user interactions for the semantics subtree.
|
||||
///
|
||||
/// Setting this true prevents user from activating pointer related
|
||||
/// [SemanticsAction]s, such as [SemanticsAction.tap] or
|
||||
/// [SemanticsAction.longPress].
|
||||
bool get blockUserActions => _blockUserActions;
|
||||
bool _blockUserActions;
|
||||
set blockUserActions(bool value) {
|
||||
if (_blockUserActions == value) {
|
||||
return;
|
||||
}
|
||||
_blockUserActions = value;
|
||||
markNeedsSemanticsUpdate();
|
||||
}
|
||||
|
||||
/// The [Locale] for the semantics subtree.
|
||||
///
|
||||
/// Setting this to null will inherit locale from ancestor semantics node
|
||||
Locale? get localeForSubtree => _localeForSubtree;
|
||||
Locale? _localeForSubtree;
|
||||
set localeForSubtree(Locale? value) {
|
||||
if (_localeForSubtree == value) {
|
||||
return;
|
||||
}
|
||||
_localeForSubtree = value;
|
||||
markNeedsSemanticsUpdate();
|
||||
}
|
||||
|
||||
void _updateAttributedFields(SemanticsProperties value) {
|
||||
_attributedLabel = _effectiveAttributedLabel(value);
|
||||
_attributedValue = _effectiveAttributedValue(value);
|
||||
_attributedIncreasedValue = _effectiveAttributedIncreasedValue(value);
|
||||
_attributedDecreasedValue = _effectiveAttributedDecreasedValue(value);
|
||||
_attributedHint = _effectiveAttributedHint(value);
|
||||
}
|
||||
|
||||
AttributedString? _effectiveAttributedLabel(SemanticsProperties value) {
|
||||
return value.attributedLabel ?? (value.label == null ? null : AttributedString(value.label!));
|
||||
}
|
||||
|
||||
AttributedString? _effectiveAttributedValue(SemanticsProperties value) {
|
||||
return value.attributedValue ?? (value.value == null ? null : AttributedString(value.value!));
|
||||
}
|
||||
|
||||
AttributedString? _effectiveAttributedIncreasedValue(SemanticsProperties value) {
|
||||
return value.attributedIncreasedValue ??
|
||||
(value.increasedValue == null ? null : AttributedString(value.increasedValue!));
|
||||
}
|
||||
|
||||
AttributedString? _effectiveAttributedDecreasedValue(SemanticsProperties value) {
|
||||
return properties.attributedDecreasedValue ??
|
||||
(value.decreasedValue == null ? null : AttributedString(value.decreasedValue!));
|
||||
}
|
||||
|
||||
AttributedString? _effectiveAttributedHint(SemanticsProperties value) {
|
||||
return value.attributedHint ?? (value.hint == null ? null : AttributedString(value.hint!));
|
||||
}
|
||||
|
||||
AttributedString? _attributedLabel;
|
||||
AttributedString? _attributedValue;
|
||||
AttributedString? _attributedIncreasedValue;
|
||||
AttributedString? _attributedDecreasedValue;
|
||||
AttributedString? _attributedHint;
|
||||
|
||||
/// If non-null, sets the [SemanticsNode.textDirection] semantic to the given
|
||||
/// value.
|
||||
///
|
||||
/// This must not be null if [SemanticsProperties.attributedLabel],
|
||||
/// [SemanticsProperties.attributedHint],
|
||||
/// [SemanticsProperties.attributedValue],
|
||||
/// [SemanticsProperties.attributedIncreasedValue], or
|
||||
/// [SemanticsProperties.attributedDecreasedValue] are not null.
|
||||
TextDirection? get textDirection => _textDirection;
|
||||
TextDirection? _textDirection;
|
||||
set textDirection(TextDirection? value) {
|
||||
if (textDirection == value) {
|
||||
return;
|
||||
}
|
||||
_textDirection = value;
|
||||
markNeedsSemanticsUpdate();
|
||||
}
|
||||
|
||||
@override
|
||||
void visitChildrenForSemantics(RenderObjectVisitor visitor) {
|
||||
if (excludeSemantics) {
|
||||
return;
|
||||
}
|
||||
super.visitChildrenForSemantics(visitor);
|
||||
}
|
||||
|
||||
@override
|
||||
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
||||
super.describeSemanticsConfiguration(config);
|
||||
config.isSemanticBoundary = container;
|
||||
config.explicitChildNodes = explicitChildNodes;
|
||||
config.isBlockingUserActions = blockUserActions;
|
||||
config.localeForSubtree = localeForSubtree;
|
||||
assert(
|
||||
((_properties.scopesRoute ?? false) && explicitChildNodes) ||
|
||||
!(_properties.scopesRoute ?? false),
|
||||
'explicitChildNodes must be set to true if scopes route is true',
|
||||
}) : super(child) {
|
||||
initSemanticsAnnotations(
|
||||
properties: properties,
|
||||
container: container,
|
||||
explicitChildNodes: explicitChildNodes,
|
||||
excludeSemantics: excludeSemantics,
|
||||
blockUserActions: blockUserActions,
|
||||
localeForSubtree: localeForSubtree,
|
||||
textDirection: textDirection,
|
||||
);
|
||||
assert(
|
||||
!((_properties.toggled ?? false) && (_properties.checked ?? false)),
|
||||
'A semantics node cannot be toggled and checked at the same time',
|
||||
);
|
||||
|
||||
if (_properties.enabled != null) {
|
||||
config.isEnabled = _properties.enabled;
|
||||
}
|
||||
if (_properties.checked != null) {
|
||||
config.isChecked = _properties.checked;
|
||||
}
|
||||
if (_properties.mixed != null) {
|
||||
config.isCheckStateMixed = _properties.mixed;
|
||||
}
|
||||
if (_properties.toggled != null) {
|
||||
config.isToggled = _properties.toggled;
|
||||
}
|
||||
if (_properties.selected != null) {
|
||||
config.isSelected = _properties.selected!;
|
||||
}
|
||||
if (_properties.button != null) {
|
||||
config.isButton = _properties.button!;
|
||||
}
|
||||
if (_properties.expanded != null) {
|
||||
config.isExpanded = _properties.expanded;
|
||||
}
|
||||
if (_properties.link != null) {
|
||||
config.isLink = _properties.link!;
|
||||
}
|
||||
if (_properties.linkUrl != null) {
|
||||
config.linkUrl = _properties.linkUrl;
|
||||
}
|
||||
if (_properties.slider != null) {
|
||||
config.isSlider = _properties.slider!;
|
||||
}
|
||||
if (_properties.keyboardKey != null) {
|
||||
config.isKeyboardKey = _properties.keyboardKey!;
|
||||
}
|
||||
if (_properties.header != null) {
|
||||
config.isHeader = _properties.header!;
|
||||
}
|
||||
if (_properties.headingLevel != null) {
|
||||
config.headingLevel = _properties.headingLevel!;
|
||||
}
|
||||
if (_properties.textField != null) {
|
||||
config.isTextField = _properties.textField!;
|
||||
}
|
||||
if (_properties.readOnly != null) {
|
||||
config.isReadOnly = _properties.readOnly!;
|
||||
}
|
||||
if (_properties.focusable != null) {
|
||||
config.isFocusable = _properties.focusable!;
|
||||
}
|
||||
if (_properties.focused != null) {
|
||||
config.isFocused = _properties.focused!;
|
||||
}
|
||||
if (_properties.inMutuallyExclusiveGroup != null) {
|
||||
config.isInMutuallyExclusiveGroup = _properties.inMutuallyExclusiveGroup!;
|
||||
}
|
||||
if (_properties.obscured != null) {
|
||||
config.isObscured = _properties.obscured!;
|
||||
}
|
||||
if (_properties.multiline != null) {
|
||||
config.isMultiline = _properties.multiline!;
|
||||
}
|
||||
if (_properties.hidden != null) {
|
||||
config.isHidden = _properties.hidden!;
|
||||
}
|
||||
if (_properties.image != null) {
|
||||
config.isImage = _properties.image!;
|
||||
}
|
||||
if (_properties.isRequired != null) {
|
||||
config.isRequired = _properties.isRequired;
|
||||
}
|
||||
if (_properties.identifier != null) {
|
||||
config.identifier = _properties.identifier!;
|
||||
}
|
||||
if (_attributedLabel != null) {
|
||||
config.attributedLabel = _attributedLabel!;
|
||||
}
|
||||
if (_attributedValue != null) {
|
||||
config.attributedValue = _attributedValue!;
|
||||
}
|
||||
if (_attributedIncreasedValue != null) {
|
||||
config.attributedIncreasedValue = _attributedIncreasedValue!;
|
||||
}
|
||||
if (_attributedDecreasedValue != null) {
|
||||
config.attributedDecreasedValue = _attributedDecreasedValue!;
|
||||
}
|
||||
if (_attributedHint != null) {
|
||||
config.attributedHint = _attributedHint!;
|
||||
}
|
||||
if (_properties.tooltip != null) {
|
||||
config.tooltip = _properties.tooltip!;
|
||||
}
|
||||
if (_properties.hintOverrides != null && _properties.hintOverrides!.isNotEmpty) {
|
||||
config.hintOverrides = _properties.hintOverrides;
|
||||
}
|
||||
if (_properties.scopesRoute != null) {
|
||||
config.scopesRoute = _properties.scopesRoute!;
|
||||
}
|
||||
if (_properties.namesRoute != null) {
|
||||
config.namesRoute = _properties.namesRoute!;
|
||||
}
|
||||
if (_properties.liveRegion != null) {
|
||||
config.liveRegion = _properties.liveRegion!;
|
||||
}
|
||||
if (_properties.maxValueLength != null) {
|
||||
config.maxValueLength = _properties.maxValueLength;
|
||||
}
|
||||
if (_properties.currentValueLength != null) {
|
||||
config.currentValueLength = _properties.currentValueLength;
|
||||
}
|
||||
if (textDirection != null) {
|
||||
config.textDirection = textDirection;
|
||||
}
|
||||
if (_properties.sortKey != null) {
|
||||
config.sortKey = _properties.sortKey;
|
||||
}
|
||||
if (_properties.tagForChildren != null) {
|
||||
config.addTagForChildren(_properties.tagForChildren!);
|
||||
}
|
||||
if (properties.role != null) {
|
||||
config.role = _properties.role!;
|
||||
}
|
||||
if (_properties.controlsNodes != null) {
|
||||
config.controlsNodes = _properties.controlsNodes;
|
||||
}
|
||||
if (config.validationResult != _properties.validationResult) {
|
||||
config.validationResult = _properties.validationResult;
|
||||
}
|
||||
|
||||
if (_properties.inputType != null) {
|
||||
config.inputType = _properties.inputType!;
|
||||
}
|
||||
|
||||
// Registering _perform* as action handlers instead of the user provided
|
||||
// ones to ensure that changing a user provided handler from a non-null to
|
||||
// another non-null value doesn't require a semantics update.
|
||||
if (_properties.onTap != null) {
|
||||
config.onTap = _performTap;
|
||||
}
|
||||
if (_properties.onLongPress != null) {
|
||||
config.onLongPress = _performLongPress;
|
||||
}
|
||||
if (_properties.onDismiss != null) {
|
||||
config.onDismiss = _performDismiss;
|
||||
}
|
||||
if (_properties.onScrollLeft != null) {
|
||||
config.onScrollLeft = _performScrollLeft;
|
||||
}
|
||||
if (_properties.onScrollRight != null) {
|
||||
config.onScrollRight = _performScrollRight;
|
||||
}
|
||||
if (_properties.onScrollUp != null) {
|
||||
config.onScrollUp = _performScrollUp;
|
||||
}
|
||||
if (_properties.onScrollDown != null) {
|
||||
config.onScrollDown = _performScrollDown;
|
||||
}
|
||||
if (_properties.onIncrease != null) {
|
||||
config.onIncrease = _performIncrease;
|
||||
}
|
||||
if (_properties.onDecrease != null) {
|
||||
config.onDecrease = _performDecrease;
|
||||
}
|
||||
if (_properties.onCopy != null) {
|
||||
config.onCopy = _performCopy;
|
||||
}
|
||||
if (_properties.onCut != null) {
|
||||
config.onCut = _performCut;
|
||||
}
|
||||
if (_properties.onPaste != null) {
|
||||
config.onPaste = _performPaste;
|
||||
}
|
||||
if (_properties.onMoveCursorForwardByCharacter != null) {
|
||||
config.onMoveCursorForwardByCharacter = _performMoveCursorForwardByCharacter;
|
||||
}
|
||||
if (_properties.onMoveCursorBackwardByCharacter != null) {
|
||||
config.onMoveCursorBackwardByCharacter = _performMoveCursorBackwardByCharacter;
|
||||
}
|
||||
if (_properties.onMoveCursorForwardByWord != null) {
|
||||
config.onMoveCursorForwardByWord = _performMoveCursorForwardByWord;
|
||||
}
|
||||
if (_properties.onMoveCursorBackwardByWord != null) {
|
||||
config.onMoveCursorBackwardByWord = _performMoveCursorBackwardByWord;
|
||||
}
|
||||
if (_properties.onSetSelection != null) {
|
||||
config.onSetSelection = _performSetSelection;
|
||||
}
|
||||
if (_properties.onSetText != null) {
|
||||
config.onSetText = _performSetText;
|
||||
}
|
||||
if (_properties.onDidGainAccessibilityFocus != null) {
|
||||
config.onDidGainAccessibilityFocus = _performDidGainAccessibilityFocus;
|
||||
}
|
||||
if (_properties.onDidLoseAccessibilityFocus != null) {
|
||||
config.onDidLoseAccessibilityFocus = _performDidLoseAccessibilityFocus;
|
||||
}
|
||||
if (_properties.onFocus != null) {
|
||||
config.onFocus = _performFocus;
|
||||
}
|
||||
if (_properties.customSemanticsActions != null) {
|
||||
config.customSemanticsActions = _properties.customSemanticsActions!;
|
||||
}
|
||||
}
|
||||
|
||||
void _performTap() {
|
||||
_properties.onTap?.call();
|
||||
}
|
||||
|
||||
void _performLongPress() {
|
||||
_properties.onLongPress?.call();
|
||||
}
|
||||
|
||||
void _performDismiss() {
|
||||
_properties.onDismiss?.call();
|
||||
}
|
||||
|
||||
void _performScrollLeft() {
|
||||
_properties.onScrollLeft?.call();
|
||||
}
|
||||
|
||||
void _performScrollRight() {
|
||||
_properties.onScrollRight?.call();
|
||||
}
|
||||
|
||||
void _performScrollUp() {
|
||||
_properties.onScrollUp?.call();
|
||||
}
|
||||
|
||||
void _performScrollDown() {
|
||||
_properties.onScrollDown?.call();
|
||||
}
|
||||
|
||||
void _performIncrease() {
|
||||
_properties.onIncrease?.call();
|
||||
}
|
||||
|
||||
void _performDecrease() {
|
||||
_properties.onDecrease?.call();
|
||||
}
|
||||
|
||||
void _performCopy() {
|
||||
_properties.onCopy?.call();
|
||||
}
|
||||
|
||||
void _performCut() {
|
||||
_properties.onCut?.call();
|
||||
}
|
||||
|
||||
void _performPaste() {
|
||||
_properties.onPaste?.call();
|
||||
}
|
||||
|
||||
void _performMoveCursorForwardByCharacter(bool extendSelection) {
|
||||
_properties.onMoveCursorForwardByCharacter?.call(extendSelection);
|
||||
}
|
||||
|
||||
void _performMoveCursorBackwardByCharacter(bool extendSelection) {
|
||||
_properties.onMoveCursorBackwardByCharacter?.call(extendSelection);
|
||||
}
|
||||
|
||||
void _performMoveCursorForwardByWord(bool extendSelection) {
|
||||
_properties.onMoveCursorForwardByWord?.call(extendSelection);
|
||||
}
|
||||
|
||||
void _performMoveCursorBackwardByWord(bool extendSelection) {
|
||||
_properties.onMoveCursorBackwardByWord?.call(extendSelection);
|
||||
}
|
||||
|
||||
void _performSetSelection(TextSelection selection) {
|
||||
_properties.onSetSelection?.call(selection);
|
||||
}
|
||||
|
||||
void _performSetText(String text) {
|
||||
_properties.onSetText?.call(text);
|
||||
}
|
||||
|
||||
void _performDidGainAccessibilityFocus() {
|
||||
_properties.onDidGainAccessibilityFocus?.call();
|
||||
}
|
||||
|
||||
void _performDidLoseAccessibilityFocus() {
|
||||
_properties.onDidLoseAccessibilityFocus?.call();
|
||||
}
|
||||
|
||||
void _performFocus() {
|
||||
_properties.onFocus?.call();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -481,3 +481,30 @@ class RenderSliverConstrainedCrossAxis extends RenderProxySliver {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Add annotations to the [SemanticsNode] for this subtree.
|
||||
class RenderSliverSemanticsAnnotations extends RenderProxySliver with SemanticsAnnotationsMixin {
|
||||
/// Creates a render object that attaches a semantic annotation.
|
||||
///
|
||||
/// If the [SemanticsProperties.attributedLabel] is not null, the [textDirection] must also not be null.
|
||||
RenderSliverSemanticsAnnotations({
|
||||
RenderSliver? child,
|
||||
required SemanticsProperties properties,
|
||||
bool container = false,
|
||||
bool explicitChildNodes = false,
|
||||
bool excludeSemantics = false,
|
||||
bool blockUserActions = false,
|
||||
Locale? localeForSubtree,
|
||||
TextDirection? textDirection,
|
||||
}) : super(child) {
|
||||
initSemanticsAnnotations(
|
||||
properties: properties,
|
||||
container: container,
|
||||
explicitChildNodes: explicitChildNodes,
|
||||
excludeSemantics: excludeSemantics,
|
||||
blockUserActions: blockUserActions,
|
||||
localeForSubtree: localeForSubtree,
|
||||
textDirection: textDirection,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3845,6 +3845,489 @@ class SliverPadding extends SingleChildRenderObjectWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// An abstract class for building widgets that annotate their subtree with a
|
||||
/// description of the meaning of the widgets.
|
||||
///
|
||||
/// {@template flutter.widgets.SemanticsBase}
|
||||
/// Used by assistive technologies, search engines, and other semantic analysis
|
||||
/// software to determine the meaning of the application.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [SemanticsProperties], which contains a complete documentation for each
|
||||
/// of the constructor parameters that belongs to semantics properties.
|
||||
/// * [RenderObject.describeSemanticsConfiguration], the rendering library API
|
||||
/// through which the [Semantics] widget and [SliverSemantics] sliver are
|
||||
/// actually implemented.
|
||||
/// * [SemanticsNode], the object used by the rendering library to represent
|
||||
/// semantics in the semantics tree.
|
||||
/// * [SemanticsDebugger], an overlay to help visualize the semantics tree. Can
|
||||
/// be enabled using [WidgetsApp.showSemanticsDebugger],
|
||||
/// [MaterialApp.showSemanticsDebugger], or [CupertinoApp.showSemanticsDebugger].
|
||||
/// * [MergeSemantics], a widget which marks a subtree as being a single node for
|
||||
/// accessibility purposes.
|
||||
/// * [ExcludeSemantics], a widget which excludes a subtree from the semantics tree
|
||||
/// (which might be useful if it is, e.g., totally decorative and not
|
||||
/// important to the user).
|
||||
/// {@endtemplate}
|
||||
@immutable
|
||||
sealed class _SemanticsBase extends SingleChildRenderObjectWidget {
|
||||
/// Creates a semantic annotation.
|
||||
///
|
||||
/// To create a `const` instance of [_SemanticsBase], use the
|
||||
/// [_SemanticsBase.fromProperties] constructor.
|
||||
///
|
||||
/// {@template flutter.widgets.SemanticsBase.constructor}
|
||||
/// See also:
|
||||
///
|
||||
/// * [SemanticsProperties], which contains a complete documentation for each
|
||||
/// of the constructor parameters that belongs to semantics properties.
|
||||
/// * [SemanticsSortKey] for a class that determines accessibility traversal
|
||||
/// order.
|
||||
/// {@endtemplate}
|
||||
// Properties added to this constructor should be marked required
|
||||
// to enforce its subclasses add it to their constructors.
|
||||
_SemanticsBase({
|
||||
Key? key,
|
||||
Widget? child,
|
||||
required bool container,
|
||||
required bool explicitChildNodes,
|
||||
required bool excludeSemantics,
|
||||
required bool blockUserActions,
|
||||
required bool? enabled,
|
||||
required bool? checked,
|
||||
required bool? mixed,
|
||||
required bool? selected,
|
||||
required bool? toggled,
|
||||
required bool? button,
|
||||
required bool? slider,
|
||||
required bool? keyboardKey,
|
||||
required bool? link,
|
||||
required Uri? linkUrl,
|
||||
required bool? header,
|
||||
required int? headingLevel,
|
||||
required bool? textField,
|
||||
required bool? readOnly,
|
||||
required bool? focusable,
|
||||
required bool? focused,
|
||||
required bool? inMutuallyExclusiveGroup,
|
||||
required bool? obscured,
|
||||
required bool? multiline,
|
||||
required bool? scopesRoute,
|
||||
required bool? namesRoute,
|
||||
required bool? hidden,
|
||||
required bool? image,
|
||||
required bool? liveRegion,
|
||||
required bool? expanded,
|
||||
required bool? isRequired,
|
||||
required int? maxValueLength,
|
||||
required int? currentValueLength,
|
||||
required String? identifier,
|
||||
required String? label,
|
||||
required AttributedString? attributedLabel,
|
||||
required String? value,
|
||||
required AttributedString? attributedValue,
|
||||
required String? increasedValue,
|
||||
required AttributedString? attributedIncreasedValue,
|
||||
required String? decreasedValue,
|
||||
required AttributedString? attributedDecreasedValue,
|
||||
required String? hint,
|
||||
required AttributedString? attributedHint,
|
||||
required String? tooltip,
|
||||
required String? onTapHint,
|
||||
required String? onLongPressHint,
|
||||
required TextDirection? textDirection,
|
||||
required SemanticsSortKey? sortKey,
|
||||
required SemanticsTag? tagForChildren,
|
||||
required VoidCallback? onTap,
|
||||
required VoidCallback? onLongPress,
|
||||
required VoidCallback? onScrollLeft,
|
||||
required VoidCallback? onScrollRight,
|
||||
required VoidCallback? onScrollUp,
|
||||
required VoidCallback? onScrollDown,
|
||||
required VoidCallback? onIncrease,
|
||||
required VoidCallback? onDecrease,
|
||||
required VoidCallback? onCopy,
|
||||
required VoidCallback? onCut,
|
||||
required VoidCallback? onPaste,
|
||||
required VoidCallback? onDismiss,
|
||||
required MoveCursorHandler? onMoveCursorForwardByCharacter,
|
||||
required MoveCursorHandler? onMoveCursorBackwardByCharacter,
|
||||
required SetSelectionHandler? onSetSelection,
|
||||
required SetTextHandler? onSetText,
|
||||
required VoidCallback? onDidGainAccessibilityFocus,
|
||||
required VoidCallback? onDidLoseAccessibilityFocus,
|
||||
required VoidCallback? onFocus,
|
||||
required Map<CustomSemanticsAction, VoidCallback>? customSemanticsActions,
|
||||
required SemanticsRole? role,
|
||||
required Set<String>? controlsNodes,
|
||||
required SemanticsValidationResult validationResult,
|
||||
required ui.SemanticsInputType? inputType,
|
||||
required Locale? localeForSubtree,
|
||||
}) : this.fromProperties(
|
||||
key: key,
|
||||
child: child,
|
||||
container: container,
|
||||
explicitChildNodes: explicitChildNodes,
|
||||
excludeSemantics: excludeSemantics,
|
||||
blockUserActions: blockUserActions,
|
||||
localeForSubtree: localeForSubtree,
|
||||
properties: SemanticsProperties(
|
||||
enabled: enabled,
|
||||
checked: checked,
|
||||
mixed: mixed,
|
||||
expanded: expanded,
|
||||
toggled: toggled,
|
||||
selected: selected,
|
||||
button: button,
|
||||
slider: slider,
|
||||
keyboardKey: keyboardKey,
|
||||
link: link,
|
||||
linkUrl: linkUrl,
|
||||
header: header,
|
||||
headingLevel: headingLevel,
|
||||
textField: textField,
|
||||
readOnly: readOnly,
|
||||
focusable: focusable,
|
||||
focused: focused,
|
||||
inMutuallyExclusiveGroup: inMutuallyExclusiveGroup,
|
||||
obscured: obscured,
|
||||
multiline: multiline,
|
||||
scopesRoute: scopesRoute,
|
||||
namesRoute: namesRoute,
|
||||
hidden: hidden,
|
||||
image: image,
|
||||
liveRegion: liveRegion,
|
||||
isRequired: isRequired,
|
||||
maxValueLength: maxValueLength,
|
||||
currentValueLength: currentValueLength,
|
||||
identifier: identifier,
|
||||
label: label,
|
||||
attributedLabel: attributedLabel,
|
||||
value: value,
|
||||
attributedValue: attributedValue,
|
||||
increasedValue: increasedValue,
|
||||
attributedIncreasedValue: attributedIncreasedValue,
|
||||
decreasedValue: decreasedValue,
|
||||
attributedDecreasedValue: attributedDecreasedValue,
|
||||
hint: hint,
|
||||
attributedHint: attributedHint,
|
||||
tooltip: tooltip,
|
||||
textDirection: textDirection,
|
||||
sortKey: sortKey,
|
||||
tagForChildren: tagForChildren,
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
onScrollLeft: onScrollLeft,
|
||||
onScrollRight: onScrollRight,
|
||||
onScrollUp: onScrollUp,
|
||||
onScrollDown: onScrollDown,
|
||||
onIncrease: onIncrease,
|
||||
onDecrease: onDecrease,
|
||||
onCopy: onCopy,
|
||||
onCut: onCut,
|
||||
onPaste: onPaste,
|
||||
onMoveCursorForwardByCharacter: onMoveCursorForwardByCharacter,
|
||||
onMoveCursorBackwardByCharacter: onMoveCursorBackwardByCharacter,
|
||||
onDidGainAccessibilityFocus: onDidGainAccessibilityFocus,
|
||||
onDidLoseAccessibilityFocus: onDidLoseAccessibilityFocus,
|
||||
onFocus: onFocus,
|
||||
onDismiss: onDismiss,
|
||||
onSetSelection: onSetSelection,
|
||||
onSetText: onSetText,
|
||||
customSemanticsActions: customSemanticsActions,
|
||||
hintOverrides: onTapHint != null || onLongPressHint != null
|
||||
? SemanticsHintOverrides(onTapHint: onTapHint, onLongPressHint: onLongPressHint)
|
||||
: null,
|
||||
role: role,
|
||||
controlsNodes: controlsNodes,
|
||||
validationResult: validationResult,
|
||||
inputType: inputType,
|
||||
),
|
||||
);
|
||||
|
||||
/// {@template flutter.widgets.SemanticsBase.fromProperties}
|
||||
/// Creates a semantic annotation using [SemanticsProperties].
|
||||
/// {@endtemplate}
|
||||
// Properties added to this constructor should be marked required
|
||||
// to enforce its subclasses add it to their constructors.
|
||||
const _SemanticsBase.fromProperties({
|
||||
super.key,
|
||||
super.child,
|
||||
required this.container,
|
||||
required this.explicitChildNodes,
|
||||
required this.excludeSemantics,
|
||||
required this.blockUserActions,
|
||||
required this.localeForSubtree,
|
||||
required this.properties,
|
||||
}) : assert(
|
||||
localeForSubtree == null || container,
|
||||
'To assign locale for subtree, this widget needs to be a '
|
||||
'container',
|
||||
);
|
||||
|
||||
/// Contains properties used by assistive technologies to make the application
|
||||
/// more accessible.
|
||||
final SemanticsProperties properties;
|
||||
|
||||
/// If [container] is true, this widget will introduce a new
|
||||
/// node in the semantics tree. Otherwise, the semantics will be
|
||||
/// merged with the semantics of any ancestors (if the ancestor allows that).
|
||||
///
|
||||
/// Whether descendants of this widget can add their semantic information to the
|
||||
/// [SemanticsNode] introduced by this configuration is controlled by
|
||||
/// [explicitChildNodes].
|
||||
final bool container;
|
||||
|
||||
/// Whether descendants of this widget are allowed to add semantic information
|
||||
/// to the [SemanticsNode] annotated by this widget.
|
||||
///
|
||||
/// When set to false descendants are allowed to annotate [SemanticsNode]s of
|
||||
/// their parent with the semantic information they want to contribute to the
|
||||
/// semantic tree.
|
||||
/// When set to true the only way for descendants to contribute semantic
|
||||
/// information to the semantic tree is to introduce new explicit
|
||||
/// [SemanticsNode]s to the tree.
|
||||
///
|
||||
/// If the semantics properties of this node include
|
||||
/// [SemanticsProperties.scopesRoute] set to true, then [explicitChildNodes]
|
||||
/// must be true also.
|
||||
///
|
||||
/// This setting is often used in combination with [SemanticsConfiguration.isSemanticBoundary]
|
||||
/// to create semantic boundaries that are either writable or not for children.
|
||||
final bool explicitChildNodes;
|
||||
|
||||
/// The [Locale] for widgets in the subtree.
|
||||
///
|
||||
/// If null, the subtree will inherit the locale form ancestor widget.
|
||||
final Locale? localeForSubtree;
|
||||
|
||||
/// Whether to replace all child semantics with this node.
|
||||
///
|
||||
/// Defaults to false.
|
||||
///
|
||||
/// When this flag is set to true, all child semantics nodes are ignored.
|
||||
/// This can be used as a convenience for cases where a child is wrapped in
|
||||
/// an [ExcludeSemantics] widget and then another [Semantics] widget.
|
||||
final bool excludeSemantics;
|
||||
|
||||
/// Whether to block user interactions for the rendering subtree.
|
||||
///
|
||||
/// Setting this to true will prevent users from interacting with The
|
||||
/// rendering object configured by this widget and its subtree through
|
||||
/// pointer-related [SemanticsAction]s in assistive technologies.
|
||||
///
|
||||
/// The [SemanticsNode] created from this widget is still focusable by
|
||||
/// assistive technologies. Only pointer-related [SemanticsAction]s, such as
|
||||
/// [SemanticsAction.tap] or its friends, are blocked.
|
||||
///
|
||||
/// If this widget is merged into a parent semantics node, only the
|
||||
/// [SemanticsAction]s of this widget and the widgets in the subtree are
|
||||
/// blocked.
|
||||
///
|
||||
/// For example using [Semantics]:
|
||||
/// ```dart
|
||||
/// void _myTap() { }
|
||||
/// void _myLongPress() { }
|
||||
///
|
||||
/// Widget build(BuildContext context) {
|
||||
/// return Semantics(
|
||||
/// onTap: _myTap,
|
||||
/// child: Semantics(
|
||||
/// blockUserActions: true,
|
||||
/// onLongPress: _myLongPress,
|
||||
/// child: const Text('label'),
|
||||
/// ),
|
||||
/// );
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The result semantics node will still have `_myTap`, but the `_myLongPress`
|
||||
/// will be blocked.
|
||||
///
|
||||
/// and similarly using [SliverSemantics]:
|
||||
/// ```dart
|
||||
/// void _myTap() { }
|
||||
/// void _myLongPress() { }
|
||||
///
|
||||
/// Widget build(BuildContext context) {
|
||||
/// return CustomScrollView(
|
||||
/// slivers: <Widget>[
|
||||
/// SliverSemantics(
|
||||
/// onTap: _myTap,
|
||||
/// sliver: SliverSemantics(
|
||||
/// blockUserActions: true,
|
||||
/// onLongPress: _myLongPress,
|
||||
/// sliver: const SliverToBoxAdapter(
|
||||
/// child: Text('label'),
|
||||
/// ),
|
||||
/// ),
|
||||
/// ),
|
||||
/// ],
|
||||
/// );
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The result semantics node will still have `_myTap`, but the `_myLongPress`
|
||||
/// will be blocked.
|
||||
final bool blockUserActions;
|
||||
|
||||
TextDirection? _getTextDirection(BuildContext context) {
|
||||
if (properties.textDirection != null) {
|
||||
return properties.textDirection;
|
||||
}
|
||||
|
||||
final bool containsText =
|
||||
properties.label != null ||
|
||||
properties.attributedLabel != null ||
|
||||
properties.value != null ||
|
||||
properties.attributedValue != null ||
|
||||
properties.increasedValue != null ||
|
||||
properties.attributedIncreasedValue != null ||
|
||||
properties.decreasedValue != null ||
|
||||
properties.attributedDecreasedValue != null ||
|
||||
properties.hint != null ||
|
||||
properties.attributedHint != null ||
|
||||
properties.tooltip != null;
|
||||
|
||||
if (!containsText) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Directionality.maybeOf(context);
|
||||
}
|
||||
}
|
||||
|
||||
/// A sliver that annotates its subtree with a description of the meaning of
|
||||
/// the slivers.
|
||||
///
|
||||
/// {@macro flutter.widgets.SemanticsBase}
|
||||
/// * [Semantics], the widget variant of this sliver.
|
||||
@immutable
|
||||
class SliverSemantics extends _SemanticsBase {
|
||||
/// Creates a semantic annotation.
|
||||
///
|
||||
/// To create a `const` instance of [SliverSemantics], use the
|
||||
/// [SliverSemantics.fromProperties] constructor.
|
||||
///
|
||||
/// {@macro flutter.widgets.SemanticsBase.constructor}
|
||||
SliverSemantics({
|
||||
super.key,
|
||||
required Widget sliver,
|
||||
super.container = false,
|
||||
super.explicitChildNodes = false,
|
||||
super.excludeSemantics = false,
|
||||
super.blockUserActions = false,
|
||||
super.enabled,
|
||||
super.checked,
|
||||
super.mixed,
|
||||
super.selected,
|
||||
super.toggled,
|
||||
super.button,
|
||||
super.slider,
|
||||
super.keyboardKey,
|
||||
super.link,
|
||||
super.linkUrl,
|
||||
super.header,
|
||||
super.headingLevel,
|
||||
super.textField,
|
||||
super.readOnly,
|
||||
super.focusable,
|
||||
super.focused,
|
||||
super.inMutuallyExclusiveGroup,
|
||||
super.obscured,
|
||||
super.multiline,
|
||||
super.scopesRoute,
|
||||
super.namesRoute,
|
||||
super.hidden,
|
||||
super.image,
|
||||
super.liveRegion,
|
||||
super.expanded,
|
||||
super.isRequired,
|
||||
super.maxValueLength,
|
||||
super.currentValueLength,
|
||||
super.identifier,
|
||||
super.label,
|
||||
super.attributedLabel,
|
||||
super.value,
|
||||
super.attributedValue,
|
||||
super.increasedValue,
|
||||
super.attributedIncreasedValue,
|
||||
super.decreasedValue,
|
||||
super.attributedDecreasedValue,
|
||||
super.hint,
|
||||
super.attributedHint,
|
||||
super.tooltip,
|
||||
super.onTapHint,
|
||||
super.onLongPressHint,
|
||||
super.textDirection,
|
||||
super.sortKey,
|
||||
super.tagForChildren,
|
||||
super.onTap,
|
||||
super.onLongPress,
|
||||
super.onScrollLeft,
|
||||
super.onScrollRight,
|
||||
super.onScrollUp,
|
||||
super.onScrollDown,
|
||||
super.onIncrease,
|
||||
super.onDecrease,
|
||||
super.onCopy,
|
||||
super.onCut,
|
||||
super.onPaste,
|
||||
super.onDismiss,
|
||||
super.onMoveCursorForwardByCharacter,
|
||||
super.onMoveCursorBackwardByCharacter,
|
||||
super.onSetSelection,
|
||||
super.onSetText,
|
||||
super.onDidGainAccessibilityFocus,
|
||||
super.onDidLoseAccessibilityFocus,
|
||||
super.onFocus,
|
||||
super.customSemanticsActions,
|
||||
super.role,
|
||||
super.controlsNodes,
|
||||
super.validationResult = SemanticsValidationResult.none,
|
||||
super.inputType,
|
||||
super.localeForSubtree,
|
||||
}) : super(child: sliver);
|
||||
|
||||
/// {@macro flutter.widgets.SemanticsBase.fromProperties}
|
||||
const SliverSemantics.fromProperties({
|
||||
super.key,
|
||||
super.child,
|
||||
super.container = false,
|
||||
super.explicitChildNodes = false,
|
||||
super.excludeSemantics = false,
|
||||
super.blockUserActions = false,
|
||||
super.localeForSubtree,
|
||||
required super.properties,
|
||||
}) : super.fromProperties();
|
||||
|
||||
@override
|
||||
RenderSliverSemanticsAnnotations createRenderObject(BuildContext context) {
|
||||
return RenderSliverSemanticsAnnotations(
|
||||
container: container,
|
||||
explicitChildNodes: explicitChildNodes,
|
||||
excludeSemantics: excludeSemantics,
|
||||
blockUserActions: blockUserActions,
|
||||
properties: properties,
|
||||
localeForSubtree: localeForSubtree,
|
||||
textDirection: _getTextDirection(context),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void updateRenderObject(BuildContext context, RenderSliverSemanticsAnnotations renderObject) {
|
||||
renderObject
|
||||
..container = container
|
||||
..explicitChildNodes = explicitChildNodes
|
||||
..excludeSemantics = excludeSemantics
|
||||
..blockUserActions = blockUserActions
|
||||
..properties = properties
|
||||
..textDirection = _getTextDirection(context)
|
||||
..localeForSubtree = localeForSubtree;
|
||||
}
|
||||
}
|
||||
|
||||
// LAYOUT NODES
|
||||
|
||||
/// Returns the [AxisDirection] in the given [Axis] in the current
|
||||
@ -7289,294 +7772,108 @@ class MetaData extends SingleChildRenderObjectWidget {
|
||||
/// A widget that annotates the widget tree with a description of the meaning of
|
||||
/// the widgets.
|
||||
///
|
||||
/// Used by assistive technologies, search engines, and other semantic analysis
|
||||
/// software to determine the meaning of the application.
|
||||
///
|
||||
/// {@youtube 560 315 https://www.youtube.com/watch?v=NvtMt_DtFrQ}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [SemanticsProperties], which contains a complete documentation for each
|
||||
/// of the constructor parameters that belongs to semantics properties.
|
||||
/// * [MergeSemantics], which marks a subtree as being a single node for
|
||||
/// accessibility purposes.
|
||||
/// * [ExcludeSemantics], which excludes a subtree from the semantics tree
|
||||
/// (which might be useful if it is, e.g., totally decorative and not
|
||||
/// important to the user).
|
||||
/// * [RenderObject.describeSemanticsConfiguration], the rendering library API
|
||||
/// through which the [Semantics] widget is actually implemented.
|
||||
/// * [SemanticsNode], the object used by the rendering library to represent
|
||||
/// semantics in the semantics tree.
|
||||
/// * [SemanticsDebugger], an overlay to help visualize the semantics tree. Can
|
||||
/// be enabled using [WidgetsApp.showSemanticsDebugger],
|
||||
/// [MaterialApp.showSemanticsDebugger], or [CupertinoApp.showSemanticsDebugger].
|
||||
/// {@macro flutter.widgets.SemanticsBase}
|
||||
/// * [SliverSemantics], the sliver variant of this widget.
|
||||
@immutable
|
||||
class Semantics extends SingleChildRenderObjectWidget {
|
||||
class Semantics extends _SemanticsBase {
|
||||
/// Creates a semantic annotation.
|
||||
///
|
||||
/// To create a `const` instance of [Semantics], use the
|
||||
/// [Semantics.fromProperties] constructor.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [SemanticsProperties], which contains a complete documentation for each
|
||||
/// of the constructor parameters that belongs to semantics properties.
|
||||
/// * [SemanticsSortKey] for a class that determines accessibility traversal
|
||||
/// order.
|
||||
/// {@macro flutter.widgets.SemanticsBase}
|
||||
Semantics({
|
||||
Key? key,
|
||||
Widget? child,
|
||||
bool container = false,
|
||||
bool explicitChildNodes = false,
|
||||
bool excludeSemantics = false,
|
||||
bool blockUserActions = false,
|
||||
bool? enabled,
|
||||
bool? checked,
|
||||
bool? mixed,
|
||||
bool? selected,
|
||||
bool? toggled,
|
||||
bool? button,
|
||||
bool? slider,
|
||||
bool? keyboardKey,
|
||||
bool? link,
|
||||
Uri? linkUrl,
|
||||
bool? header,
|
||||
int? headingLevel,
|
||||
bool? textField,
|
||||
bool? readOnly,
|
||||
bool? focusable,
|
||||
bool? focused,
|
||||
bool? inMutuallyExclusiveGroup,
|
||||
bool? obscured,
|
||||
bool? multiline,
|
||||
bool? scopesRoute,
|
||||
bool? namesRoute,
|
||||
bool? hidden,
|
||||
bool? image,
|
||||
bool? liveRegion,
|
||||
bool? expanded,
|
||||
bool? isRequired,
|
||||
int? maxValueLength,
|
||||
int? currentValueLength,
|
||||
String? identifier,
|
||||
String? label,
|
||||
AttributedString? attributedLabel,
|
||||
String? value,
|
||||
AttributedString? attributedValue,
|
||||
String? increasedValue,
|
||||
AttributedString? attributedIncreasedValue,
|
||||
String? decreasedValue,
|
||||
AttributedString? attributedDecreasedValue,
|
||||
String? hint,
|
||||
AttributedString? attributedHint,
|
||||
String? tooltip,
|
||||
String? onTapHint,
|
||||
String? onLongPressHint,
|
||||
TextDirection? textDirection,
|
||||
SemanticsSortKey? sortKey,
|
||||
SemanticsTag? tagForChildren,
|
||||
VoidCallback? onTap,
|
||||
VoidCallback? onLongPress,
|
||||
VoidCallback? onScrollLeft,
|
||||
VoidCallback? onScrollRight,
|
||||
VoidCallback? onScrollUp,
|
||||
VoidCallback? onScrollDown,
|
||||
VoidCallback? onIncrease,
|
||||
VoidCallback? onDecrease,
|
||||
VoidCallback? onCopy,
|
||||
VoidCallback? onCut,
|
||||
VoidCallback? onPaste,
|
||||
VoidCallback? onDismiss,
|
||||
MoveCursorHandler? onMoveCursorForwardByCharacter,
|
||||
MoveCursorHandler? onMoveCursorBackwardByCharacter,
|
||||
SetSelectionHandler? onSetSelection,
|
||||
SetTextHandler? onSetText,
|
||||
VoidCallback? onDidGainAccessibilityFocus,
|
||||
VoidCallback? onDidLoseAccessibilityFocus,
|
||||
VoidCallback? onFocus,
|
||||
Map<CustomSemanticsAction, VoidCallback>? customSemanticsActions,
|
||||
SemanticsRole? role,
|
||||
Set<String>? controlsNodes,
|
||||
SemanticsValidationResult validationResult = SemanticsValidationResult.none,
|
||||
ui.SemanticsInputType? inputType,
|
||||
Locale? localeForSubtree,
|
||||
}) : this.fromProperties(
|
||||
key: key,
|
||||
child: child,
|
||||
container: container,
|
||||
explicitChildNodes: explicitChildNodes,
|
||||
excludeSemantics: excludeSemantics,
|
||||
blockUserActions: blockUserActions,
|
||||
localeForSubtree: localeForSubtree,
|
||||
properties: SemanticsProperties(
|
||||
enabled: enabled,
|
||||
checked: checked,
|
||||
mixed: mixed,
|
||||
expanded: expanded,
|
||||
toggled: toggled,
|
||||
selected: selected,
|
||||
button: button,
|
||||
slider: slider,
|
||||
keyboardKey: keyboardKey,
|
||||
link: link,
|
||||
linkUrl: linkUrl,
|
||||
header: header,
|
||||
headingLevel: headingLevel,
|
||||
textField: textField,
|
||||
readOnly: readOnly,
|
||||
focusable: focusable,
|
||||
focused: focused,
|
||||
inMutuallyExclusiveGroup: inMutuallyExclusiveGroup,
|
||||
obscured: obscured,
|
||||
multiline: multiline,
|
||||
scopesRoute: scopesRoute,
|
||||
namesRoute: namesRoute,
|
||||
hidden: hidden,
|
||||
image: image,
|
||||
liveRegion: liveRegion,
|
||||
isRequired: isRequired,
|
||||
maxValueLength: maxValueLength,
|
||||
currentValueLength: currentValueLength,
|
||||
identifier: identifier,
|
||||
label: label,
|
||||
attributedLabel: attributedLabel,
|
||||
value: value,
|
||||
attributedValue: attributedValue,
|
||||
increasedValue: increasedValue,
|
||||
attributedIncreasedValue: attributedIncreasedValue,
|
||||
decreasedValue: decreasedValue,
|
||||
attributedDecreasedValue: attributedDecreasedValue,
|
||||
hint: hint,
|
||||
attributedHint: attributedHint,
|
||||
tooltip: tooltip,
|
||||
textDirection: textDirection,
|
||||
sortKey: sortKey,
|
||||
tagForChildren: tagForChildren,
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
onScrollLeft: onScrollLeft,
|
||||
onScrollRight: onScrollRight,
|
||||
onScrollUp: onScrollUp,
|
||||
onScrollDown: onScrollDown,
|
||||
onIncrease: onIncrease,
|
||||
onDecrease: onDecrease,
|
||||
onCopy: onCopy,
|
||||
onCut: onCut,
|
||||
onPaste: onPaste,
|
||||
onMoveCursorForwardByCharacter: onMoveCursorForwardByCharacter,
|
||||
onMoveCursorBackwardByCharacter: onMoveCursorBackwardByCharacter,
|
||||
onDidGainAccessibilityFocus: onDidGainAccessibilityFocus,
|
||||
onDidLoseAccessibilityFocus: onDidLoseAccessibilityFocus,
|
||||
onFocus: onFocus,
|
||||
onDismiss: onDismiss,
|
||||
onSetSelection: onSetSelection,
|
||||
onSetText: onSetText,
|
||||
customSemanticsActions: customSemanticsActions,
|
||||
hintOverrides: onTapHint != null || onLongPressHint != null
|
||||
? SemanticsHintOverrides(onTapHint: onTapHint, onLongPressHint: onLongPressHint)
|
||||
: null,
|
||||
role: role,
|
||||
controlsNodes: controlsNodes,
|
||||
validationResult: validationResult,
|
||||
inputType: inputType,
|
||||
),
|
||||
);
|
||||
super.key,
|
||||
super.child,
|
||||
super.container = false,
|
||||
super.explicitChildNodes = false,
|
||||
super.excludeSemantics = false,
|
||||
super.blockUserActions = false,
|
||||
super.enabled,
|
||||
super.checked,
|
||||
super.mixed,
|
||||
super.selected,
|
||||
super.toggled,
|
||||
super.button,
|
||||
super.slider,
|
||||
super.keyboardKey,
|
||||
super.link,
|
||||
super.linkUrl,
|
||||
super.header,
|
||||
super.headingLevel,
|
||||
super.textField,
|
||||
super.readOnly,
|
||||
super.focusable,
|
||||
super.focused,
|
||||
super.inMutuallyExclusiveGroup,
|
||||
super.obscured,
|
||||
super.multiline,
|
||||
super.scopesRoute,
|
||||
super.namesRoute,
|
||||
super.hidden,
|
||||
super.image,
|
||||
super.liveRegion,
|
||||
super.expanded,
|
||||
super.isRequired,
|
||||
super.maxValueLength,
|
||||
super.currentValueLength,
|
||||
super.identifier,
|
||||
super.label,
|
||||
super.attributedLabel,
|
||||
super.value,
|
||||
super.attributedValue,
|
||||
super.increasedValue,
|
||||
super.attributedIncreasedValue,
|
||||
super.decreasedValue,
|
||||
super.attributedDecreasedValue,
|
||||
super.hint,
|
||||
super.attributedHint,
|
||||
super.tooltip,
|
||||
super.onTapHint,
|
||||
super.onLongPressHint,
|
||||
super.textDirection,
|
||||
super.sortKey,
|
||||
super.tagForChildren,
|
||||
super.onTap,
|
||||
super.onLongPress,
|
||||
super.onScrollLeft,
|
||||
super.onScrollRight,
|
||||
super.onScrollUp,
|
||||
super.onScrollDown,
|
||||
super.onIncrease,
|
||||
super.onDecrease,
|
||||
super.onCopy,
|
||||
super.onCut,
|
||||
super.onPaste,
|
||||
super.onDismiss,
|
||||
super.onMoveCursorForwardByCharacter,
|
||||
super.onMoveCursorBackwardByCharacter,
|
||||
super.onSetSelection,
|
||||
super.onSetText,
|
||||
super.onDidGainAccessibilityFocus,
|
||||
super.onDidLoseAccessibilityFocus,
|
||||
super.onFocus,
|
||||
super.customSemanticsActions,
|
||||
super.role,
|
||||
super.controlsNodes,
|
||||
super.validationResult = SemanticsValidationResult.none,
|
||||
super.inputType,
|
||||
super.localeForSubtree,
|
||||
});
|
||||
|
||||
/// Creates a semantic annotation using [SemanticsProperties].
|
||||
/// {@macro flutter.widgets.SemanticsBase.fromProperties}
|
||||
const Semantics.fromProperties({
|
||||
super.key,
|
||||
super.child,
|
||||
this.container = false,
|
||||
this.explicitChildNodes = false,
|
||||
this.excludeSemantics = false,
|
||||
this.blockUserActions = false,
|
||||
this.localeForSubtree,
|
||||
required this.properties,
|
||||
}) : assert(
|
||||
localeForSubtree == null || container,
|
||||
'To assign locale for subtree, this widget needs to be a '
|
||||
'container',
|
||||
);
|
||||
|
||||
/// Contains properties used by assistive technologies to make the application
|
||||
/// more accessible.
|
||||
final SemanticsProperties properties;
|
||||
|
||||
/// If [container] is true, this widget will introduce a new
|
||||
/// node in the semantics tree. Otherwise, the semantics will be
|
||||
/// merged with the semantics of any ancestors (if the ancestor allows that).
|
||||
///
|
||||
/// Whether descendants of this widget can add their semantic information to the
|
||||
/// [SemanticsNode] introduced by this configuration is controlled by
|
||||
/// [explicitChildNodes].
|
||||
final bool container;
|
||||
|
||||
/// Whether descendants of this widget are allowed to add semantic information
|
||||
/// to the [SemanticsNode] annotated by this widget.
|
||||
///
|
||||
/// When set to false descendants are allowed to annotate [SemanticsNode]s of
|
||||
/// their parent with the semantic information they want to contribute to the
|
||||
/// semantic tree.
|
||||
/// When set to true the only way for descendants to contribute semantic
|
||||
/// information to the semantic tree is to introduce new explicit
|
||||
/// [SemanticsNode]s to the tree.
|
||||
///
|
||||
/// If the semantics properties of this node include
|
||||
/// [SemanticsProperties.scopesRoute] set to true, then [explicitChildNodes]
|
||||
/// must be true also.
|
||||
///
|
||||
/// This setting is often used in combination with [SemanticsConfiguration.isSemanticBoundary]
|
||||
/// to create semantic boundaries that are either writable or not for children.
|
||||
final bool explicitChildNodes;
|
||||
|
||||
/// The [Locale] for widgets in the subtree.
|
||||
///
|
||||
/// If null, the subtree will inherit the locale form ancestor widget.
|
||||
final Locale? localeForSubtree;
|
||||
|
||||
/// Whether to replace all child semantics with this node.
|
||||
///
|
||||
/// Defaults to false.
|
||||
///
|
||||
/// When this flag is set to true, all child semantics nodes are ignored.
|
||||
/// This can be used as a convenience for cases where a child is wrapped in
|
||||
/// an [ExcludeSemantics] widget and then another [Semantics] widget.
|
||||
final bool excludeSemantics;
|
||||
|
||||
/// Whether to block user interactions for the rendering subtree.
|
||||
///
|
||||
/// Setting this to true will prevent users from interacting with The
|
||||
/// rendering object configured by this widget and its subtree through
|
||||
/// pointer-related [SemanticsAction]s in assistive technologies.
|
||||
///
|
||||
/// The [SemanticsNode] created from this widget is still focusable by
|
||||
/// assistive technologies. Only pointer-related [SemanticsAction]s, such as
|
||||
/// [SemanticsAction.tap] or its friends, are blocked.
|
||||
///
|
||||
/// If this widget is merged into a parent semantics node, only the
|
||||
/// [SemanticsAction]s of this widget and the widgets in the subtree are
|
||||
/// blocked.
|
||||
///
|
||||
/// For example:
|
||||
/// ```dart
|
||||
/// void _myTap() { }
|
||||
/// void _myLongPress() { }
|
||||
///
|
||||
/// Widget build(BuildContext context) {
|
||||
/// return Semantics(
|
||||
/// onTap: _myTap,
|
||||
/// child: Semantics(
|
||||
/// blockUserActions: true,
|
||||
/// onLongPress: _myLongPress,
|
||||
/// child: const Text('label'),
|
||||
/// ),
|
||||
/// );
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The result semantics node will still have `_myTap`, but the `_myLongPress`
|
||||
/// will be blocked.
|
||||
final bool blockUserActions;
|
||||
super.container = false,
|
||||
super.explicitChildNodes = false,
|
||||
super.excludeSemantics = false,
|
||||
super.blockUserActions = false,
|
||||
super.localeForSubtree,
|
||||
required super.properties,
|
||||
}) : super.fromProperties();
|
||||
|
||||
@override
|
||||
RenderSemanticsAnnotations createRenderObject(BuildContext context) {
|
||||
@ -7591,31 +7888,6 @@ class Semantics extends SingleChildRenderObjectWidget {
|
||||
);
|
||||
}
|
||||
|
||||
TextDirection? _getTextDirection(BuildContext context) {
|
||||
if (properties.textDirection != null) {
|
||||
return properties.textDirection;
|
||||
}
|
||||
|
||||
final bool containsText =
|
||||
properties.label != null ||
|
||||
properties.attributedLabel != null ||
|
||||
properties.value != null ||
|
||||
properties.attributedValue != null ||
|
||||
properties.increasedValue != null ||
|
||||
properties.attributedIncreasedValue != null ||
|
||||
properties.decreasedValue != null ||
|
||||
properties.attributedDecreasedValue != null ||
|
||||
properties.hint != null ||
|
||||
properties.attributedHint != null ||
|
||||
properties.tooltip != null;
|
||||
|
||||
if (!containsText) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Directionality.maybeOf(context);
|
||||
}
|
||||
|
||||
@override
|
||||
void updateRenderObject(BuildContext context, RenderSemanticsAnnotations renderObject) {
|
||||
renderObject
|
||||
|
||||
2931
packages/flutter/test/widgets/sliversemantics_test.dart
Normal file
2931
packages/flutter/test/widgets/sliversemantics_test.dart
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user