Remove semantics boundary from gesture detector AND MORE (#13983)
`RenderSemanticsGestureHandler` is no longer a semantics boundary, which allows us to correctly mark disabled buttons as disabled without having their semantics size and semantics node id change unexpectedly. Fixes https://github.com/flutter/flutter/issues/12589. Fixes https://github.com/flutter/flutter/issues/11991. See also https://github.com/flutter/flutter/issues/11993. This change also required some refactoring to how we deal with `twoPaneSemantics` scrolling as it previously relied on `RenderSemanticsGestureHandler` being a semantics boundary. This should also make the underlying logic easier to understand. In addition, the following minor changes are included in this PR: * Removal of orphaned and unused `SemanticsConfiguration.isMergingDescendantsIntoOneNode`. * Logic optimizations for `markNeedsSemanticsUpdate` . * Fix for edge case where `MergeSemantics` failed to merge semantics. * Use of emojis to better indicate leaf merging in the printed semantics tree. * Better assert message for adding invisible child semantics nodes. * Make some semantics tests robuster by not relying on creation order of SemanticsNode ids across test boundaries. Fixes https://github.com/flutter/flutter/issues/13943.
This commit is contained in:
parent
33d8a03545
commit
8a6e973739
@ -332,7 +332,7 @@ class _MaterialButtonState extends State<MaterialButton> {
|
|||||||
child: new Center(
|
child: new Center(
|
||||||
widthFactor: 1.0,
|
widthFactor: 1.0,
|
||||||
heightFactor: 1.0,
|
heightFactor: 1.0,
|
||||||
child: new Semantics(button: true, child: widget.child),
|
child: widget.child,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -352,12 +352,17 @@ class _MaterialButtonState extends State<MaterialButton> {
|
|||||||
child: contents
|
child: contents
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return new ConstrainedBox(
|
return new Semantics(
|
||||||
constraints: new BoxConstraints(
|
container: true,
|
||||||
minWidth: widget.minWidth ?? buttonTheme.minWidth,
|
button: true,
|
||||||
minHeight: height,
|
enabled: widget.enabled,
|
||||||
|
child: new ConstrainedBox(
|
||||||
|
constraints: new BoxConstraints(
|
||||||
|
minWidth: widget.minWidth ?? buttonTheme.minWidth,
|
||||||
|
minHeight: height,
|
||||||
|
),
|
||||||
|
child: contents
|
||||||
),
|
),
|
||||||
child: contents
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2243,7 +2243,7 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
|
|||||||
// RenderObject are still up-to date. Therefore, we will later only rebuild
|
// RenderObject are still up-to date. Therefore, we will later only rebuild
|
||||||
// the semantics subtree starting at th identified semantics boundary.
|
// the semantics subtree starting at th identified semantics boundary.
|
||||||
|
|
||||||
final bool wasSemanticsBoundary = _cachedSemanticsConfiguration?.isSemanticBoundary == true;
|
final bool wasSemanticsBoundary = _semantics != null && _cachedSemanticsConfiguration?.isSemanticBoundary == true;
|
||||||
_cachedSemanticsConfiguration = null;
|
_cachedSemanticsConfiguration = null;
|
||||||
bool isEffectiveSemanticsBoundary = _semanticsConfiguration.isSemanticBoundary && wasSemanticsBoundary;
|
bool isEffectiveSemanticsBoundary = _semanticsConfiguration.isSemanticBoundary && wasSemanticsBoundary;
|
||||||
RenderObject node = this;
|
RenderObject node = this;
|
||||||
@ -2254,7 +2254,6 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
|
|||||||
node._needsSemanticsUpdate = true;
|
node._needsSemanticsUpdate = true;
|
||||||
|
|
||||||
node = node.parent;
|
node = node.parent;
|
||||||
node._cachedSemanticsConfiguration = null;
|
|
||||||
isEffectiveSemanticsBoundary = node._semanticsConfiguration.isSemanticBoundary;
|
isEffectiveSemanticsBoundary = node._semanticsConfiguration.isSemanticBoundary;
|
||||||
if (isEffectiveSemanticsBoundary && node._semantics == null) {
|
if (isEffectiveSemanticsBoundary && node._semantics == null) {
|
||||||
// We have reached a semantics boundary that doesn't own a semantics node.
|
// We have reached a semantics boundary that doesn't own a semantics node.
|
||||||
@ -2274,10 +2273,6 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
|
|||||||
owner._nodesNeedingSemantics.remove(this);
|
owner._nodesNeedingSemantics.remove(this);
|
||||||
}
|
}
|
||||||
if (!node._needsSemanticsUpdate) {
|
if (!node._needsSemanticsUpdate) {
|
||||||
if (node != this) {
|
|
||||||
// Reset for `this` happened above already.
|
|
||||||
node._cachedSemanticsConfiguration = null;
|
|
||||||
}
|
|
||||||
node._needsSemanticsUpdate = true;
|
node._needsSemanticsUpdate = true;
|
||||||
if (owner != null) {
|
if (owner != null) {
|
||||||
assert(node._semanticsConfiguration.isSemanticBoundary || node.parent is! RenderObject);
|
assert(node._semanticsConfiguration.isSemanticBoundary || node.parent is! RenderObject);
|
||||||
|
@ -2565,37 +2565,6 @@ class RenderSemanticsGestureHandler extends RenderProxyBox {
|
|||||||
_onVerticalDragUpdate = onVerticalDragUpdate,
|
_onVerticalDragUpdate = onVerticalDragUpdate,
|
||||||
super(child);
|
super(child);
|
||||||
|
|
||||||
/// When a [SemanticsNode] that is a direct child of this object's
|
|
||||||
/// [SemanticsNode] is tagged with [excludeFromScrolling] it will not be
|
|
||||||
/// part of the scrolling area for semantic purposes.
|
|
||||||
///
|
|
||||||
/// This behavior is only active if the [SemanticsNode] of this
|
|
||||||
/// [RenderSemanticsGestureHandler] is tagged with [useTwoPaneSemantics].
|
|
||||||
/// Otherwise, the [excludeFromScrolling] tag is ignored.
|
|
||||||
///
|
|
||||||
/// As an example, a [RenderSliver] that stays on the screen within a
|
|
||||||
/// [Scrollable] even though the user has scrolled past it (e.g. a pinned app
|
|
||||||
/// bar) can tag its [SemanticsNode] with [excludeFromScrolling] to indicate
|
|
||||||
/// that it should no longer be considered for semantic actions related to
|
|
||||||
/// scrolling.
|
|
||||||
static const SemanticsTag excludeFromScrolling = const SemanticsTag('RenderSemanticsGestureHandler.excludeFromScrolling');
|
|
||||||
|
|
||||||
/// If the [SemanticsNode] of this [RenderSemanticsGestureHandler] is tagged
|
|
||||||
/// with [useTwoPaneSemantics], two semantics nodes will be used to represent
|
|
||||||
/// this render object in the semantics tree.
|
|
||||||
///
|
|
||||||
/// Two semantics nodes are necessary to exclude certain child nodes (via the
|
|
||||||
/// [excludeFromScrolling] tag) from the scrollable area for semantic
|
|
||||||
/// purposes.
|
|
||||||
///
|
|
||||||
/// If this tag is used, the first "outer" semantics node is the regular node
|
|
||||||
/// of this object. The second "inner" node is introduced as a child to that
|
|
||||||
/// node. All scrollable children become children of the inner node, which has
|
|
||||||
/// the semantic scrolling logic enabled. All children that have been
|
|
||||||
/// excluded from scrolling with [excludeFromScrolling] are turned into
|
|
||||||
/// children of the outer node.
|
|
||||||
static const SemanticsTag useTwoPaneSemantics = const SemanticsTag('RenderSemanticsGestureHandler.twoPane');
|
|
||||||
|
|
||||||
/// If non-null, the set of actions to allow. Other actions will be omitted,
|
/// If non-null, the set of actions to allow. Other actions will be omitted,
|
||||||
/// even if their callback is provided.
|
/// even if their callback is provided.
|
||||||
///
|
///
|
||||||
@ -2673,24 +2642,10 @@ class RenderSemanticsGestureHandler extends RenderProxyBox {
|
|||||||
/// leftwards drag.
|
/// leftwards drag.
|
||||||
double scrollFactor;
|
double scrollFactor;
|
||||||
|
|
||||||
bool get _hasHandlers {
|
|
||||||
return onTap != null
|
|
||||||
|| onLongPress != null
|
|
||||||
|| onHorizontalDragUpdate != null
|
|
||||||
|| onVerticalDragUpdate != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
||||||
super.describeSemanticsConfiguration(config);
|
super.describeSemanticsConfiguration(config);
|
||||||
|
|
||||||
config.isSemanticBoundary = _hasHandlers;
|
|
||||||
|
|
||||||
// TODO(goderbauer): this needs to be set even when there is only potential
|
|
||||||
// for this to become a scroll view.
|
|
||||||
config.explicitChildNodes = onHorizontalDragUpdate != null
|
|
||||||
|| onVerticalDragUpdate != null;
|
|
||||||
|
|
||||||
if (onTap != null && _isValidAction(SemanticsAction.tap))
|
if (onTap != null && _isValidAction(SemanticsAction.tap))
|
||||||
config.onTap = onTap;
|
config.onTap = onTap;
|
||||||
if (onLongPress != null && _isValidAction(SemanticsAction.longPress))
|
if (onLongPress != null && _isValidAction(SemanticsAction.longPress))
|
||||||
@ -2713,42 +2668,6 @@ class RenderSemanticsGestureHandler extends RenderProxyBox {
|
|||||||
return validActions == null || validActions.contains(action);
|
return validActions == null || validActions.contains(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
SemanticsNode _innerNode;
|
|
||||||
SemanticsNode _annotatedNode;
|
|
||||||
|
|
||||||
/// Sends a [SemanticsEvent] in the context of the [SemanticsNode] that is
|
|
||||||
/// annotated with this object's semantics information.
|
|
||||||
void sendSemanticsEvent(SemanticsEvent event) {
|
|
||||||
_annotatedNode?.sendEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void assembleSemanticsNode(SemanticsNode node, SemanticsConfiguration config, Iterable<SemanticsNode> children) {
|
|
||||||
if (children.isEmpty || !children.first.isTagged(useTwoPaneSemantics)) {
|
|
||||||
_annotatedNode = node;
|
|
||||||
super.assembleSemanticsNode(node, config, children);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_innerNode ??= new SemanticsNode(showOnScreen: showOnScreen);
|
|
||||||
_innerNode
|
|
||||||
..isMergedIntoParent = node.isPartOfNodeMerging
|
|
||||||
..rect = Offset.zero & node.rect.size;
|
|
||||||
_annotatedNode = _innerNode;
|
|
||||||
|
|
||||||
final List<SemanticsNode> excluded = <SemanticsNode>[_innerNode];
|
|
||||||
final List<SemanticsNode> included = <SemanticsNode>[];
|
|
||||||
for (SemanticsNode child in children) {
|
|
||||||
assert(child.isTagged(useTwoPaneSemantics));
|
|
||||||
if (child.isTagged(excludeFromScrolling))
|
|
||||||
excluded.add(child);
|
|
||||||
else
|
|
||||||
included.add(child);
|
|
||||||
}
|
|
||||||
node.updateWith(config: null, childrenInInversePaintOrder: excluded);
|
|
||||||
_innerNode.updateWith(config: config, childrenInInversePaintOrder: included);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _performSemanticScrollLeft() {
|
void _performSemanticScrollLeft() {
|
||||||
if (onHorizontalDragUpdate != null) {
|
if (onHorizontalDragUpdate != null) {
|
||||||
final double primaryDelta = size.width * -scrollFactor;
|
final double primaryDelta = size.width * -scrollFactor;
|
||||||
|
@ -14,8 +14,8 @@ import 'package:vector_math/vector_math_64.dart';
|
|||||||
import 'binding.dart';
|
import 'binding.dart';
|
||||||
import 'box.dart';
|
import 'box.dart';
|
||||||
import 'object.dart';
|
import 'object.dart';
|
||||||
import 'proxy_box.dart';
|
|
||||||
import 'sliver.dart';
|
import 'sliver.dart';
|
||||||
|
import 'viewport.dart';
|
||||||
import 'viewport_offset.dart';
|
import 'viewport_offset.dart';
|
||||||
|
|
||||||
/// A base class for slivers that have a [RenderBox] child which scrolls
|
/// A base class for slivers that have a [RenderBox] child which scrolls
|
||||||
@ -225,7 +225,7 @@ abstract class RenderSliverPersistentHeader extends RenderSliver with RenderObje
|
|||||||
super.describeSemanticsConfiguration(config);
|
super.describeSemanticsConfiguration(config);
|
||||||
|
|
||||||
if (_excludeFromSemanticsScrolling)
|
if (_excludeFromSemanticsScrolling)
|
||||||
config.addTagForChildren(RenderSemanticsGestureHandler.excludeFromScrolling);
|
config.addTagForChildren(RenderViewport.excludeFromScrolling);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -12,7 +12,6 @@ import 'package:vector_math/vector_math_64.dart';
|
|||||||
import 'binding.dart';
|
import 'binding.dart';
|
||||||
import 'box.dart';
|
import 'box.dart';
|
||||||
import 'object.dart';
|
import 'object.dart';
|
||||||
import 'proxy_box.dart';
|
|
||||||
import 'sliver.dart';
|
import 'sliver.dart';
|
||||||
import 'viewport_offset.dart';
|
import 'viewport_offset.dart';
|
||||||
|
|
||||||
@ -91,12 +90,11 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
|
|||||||
_crossAxisDirection = crossAxisDirection,
|
_crossAxisDirection = crossAxisDirection,
|
||||||
_offset = offset;
|
_offset = offset;
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
||||||
super.describeSemanticsConfiguration(config);
|
super.describeSemanticsConfiguration(config);
|
||||||
|
|
||||||
config.addTagForChildren(RenderSemanticsGestureHandler.useTwoPaneSemantics);
|
config.addTagForChildren(RenderViewport.useTwoPaneSemantics);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -746,6 +744,36 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat
|
|||||||
_center = firstChild;
|
_center = firstChild;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If a [RenderAbstractViewport] overrides
|
||||||
|
/// [RenderObject.describeSemanticsConfiguration] to add the [SemanticsTag]
|
||||||
|
/// [useTwoPaneSemantics] to its [SemanticsConfiguration], two semantics nodes
|
||||||
|
/// will be used to represent the viewport with its associated scrolling
|
||||||
|
/// actions in the semantics tree.
|
||||||
|
///
|
||||||
|
/// Two semantics nodes (an inner and an outer node) are necessary to exclude
|
||||||
|
/// certain child nodes (via the [excludeFromScrolling] tag) from the
|
||||||
|
/// scrollable area for semantic purposes: The [SemanticsNode]s of children
|
||||||
|
/// that should be excluded from scrolling will be attached to the outer node.
|
||||||
|
/// The semantic scrolling actions and the [SemanticsNode]s of scrollable
|
||||||
|
/// children will be attached to the inner node, which itself is a child of
|
||||||
|
/// the outer node.
|
||||||
|
static const SemanticsTag useTwoPaneSemantics = const SemanticsTag('RenderViewport.twoPane');
|
||||||
|
|
||||||
|
/// When a top-level [SemanticsNode] below a [RenderAbstractViewport] is
|
||||||
|
/// tagged with [excludeFromScrolling] it will not be part of the scrolling
|
||||||
|
/// area for semantic purposes.
|
||||||
|
///
|
||||||
|
/// This behavior is only active if the [RenderAbstractViewport]
|
||||||
|
/// tagged its [SemanticsConfiguration] with [useTwoPaneSemantics].
|
||||||
|
/// Otherwise, the [excludeFromScrolling] tag is ignored.
|
||||||
|
///
|
||||||
|
/// As an example, a [RenderSliver] that stays on the screen within a
|
||||||
|
/// [Scrollable] even though the user has scrolled past it (e.g. a pinned app
|
||||||
|
/// bar) can tag its [SemanticsNode] with [excludeFromScrolling] to indicate
|
||||||
|
/// that it should no longer be considered for semantic actions related to
|
||||||
|
/// scrolling.
|
||||||
|
static const SemanticsTag excludeFromScrolling = const SemanticsTag('RenderViewport.excludeFromScrolling');
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void setupParentData(RenderObject child) {
|
void setupParentData(RenderObject child) {
|
||||||
if (child.parentData is! SliverPhysicalContainerParentData)
|
if (child.parentData is! SliverPhysicalContainerParentData)
|
||||||
|
@ -654,6 +654,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
assert(!newChildren.any((SemanticsNode node) => node.isMergedIntoParent) || isPartOfNodeMerging);
|
||||||
|
|
||||||
_debugPreviousSnapshot = new List<SemanticsNode>.from(newChildren);
|
_debugPreviousSnapshot = new List<SemanticsNode>.from(newChildren);
|
||||||
|
|
||||||
@ -677,7 +678,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
|||||||
}
|
}
|
||||||
if (newChildren != null) {
|
if (newChildren != null) {
|
||||||
for (SemanticsNode child in newChildren) {
|
for (SemanticsNode child in newChildren) {
|
||||||
assert(!child.isInvisible, 'Child with id ${child.id} is invisible and should not be added to tree.');
|
assert(!child.isInvisible, '$child is invisible and should not be added as child of $this.');
|
||||||
child._dead = false;
|
child._dead = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1072,7 +1073,8 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
|||||||
hideOwner = inDirtyNodes;
|
hideOwner = inDirtyNodes;
|
||||||
}
|
}
|
||||||
properties.add(new DiagnosticsProperty<SemanticsOwner>('owner', owner, level: hideOwner ? DiagnosticLevel.hidden : DiagnosticLevel.info));
|
properties.add(new DiagnosticsProperty<SemanticsOwner>('owner', owner, level: hideOwner ? DiagnosticLevel.hidden : DiagnosticLevel.info));
|
||||||
properties.add(new FlagProperty('isPartOfNodeMerging', value: isPartOfNodeMerging, ifTrue: 'leaf merge'));
|
properties.add(new FlagProperty('isMergedIntoParent', value: isMergedIntoParent, ifTrue: 'merged up ⬆️'));
|
||||||
|
properties.add(new FlagProperty('mergeAllDescendantsIntoThisNode', value: mergeAllDescendantsIntoThisNode, ifTrue: 'merge boundary ⛔️'));
|
||||||
final Offset offset = transform != null ? MatrixUtils.getAsTranslation(transform) : null;
|
final Offset offset = transform != null ? MatrixUtils.getAsTranslation(transform) : null;
|
||||||
if (offset != null) {
|
if (offset != null) {
|
||||||
properties.add(new DiagnosticsProperty<Rect>('rect', rect.shift(offset), showName: false));
|
properties.add(new DiagnosticsProperty<Rect>('rect', rect.shift(offset), showName: false));
|
||||||
@ -1344,7 +1346,7 @@ class SemanticsConfiguration {
|
|||||||
bool get isSemanticBoundary => _isSemanticBoundary;
|
bool get isSemanticBoundary => _isSemanticBoundary;
|
||||||
bool _isSemanticBoundary = false;
|
bool _isSemanticBoundary = false;
|
||||||
set isSemanticBoundary(bool value) {
|
set isSemanticBoundary(bool value) {
|
||||||
assert(!isMergingDescendantsIntoOneNode || value);
|
assert(!isMergingSemanticsOfDescendants || value);
|
||||||
_isSemanticBoundary = value;
|
_isSemanticBoundary = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1380,20 +1382,6 @@ class SemanticsConfiguration {
|
|||||||
/// determine if a node is previous to this one.
|
/// determine if a node is previous to this one.
|
||||||
bool isBlockingSemanticsOfPreviouslyPaintedNodes = false;
|
bool isBlockingSemanticsOfPreviouslyPaintedNodes = false;
|
||||||
|
|
||||||
/// Whether the semantics information of all descendants should be merged
|
|
||||||
/// into the owning [RenderObject] semantics node.
|
|
||||||
///
|
|
||||||
/// When this is set to true the [SemanticsNode] of the owning [RenderObject]
|
|
||||||
/// will not have any children.
|
|
||||||
///
|
|
||||||
/// Setting this to true requires that [isSemanticBoundary] is also true.
|
|
||||||
bool get isMergingDescendantsIntoOneNode => _isMergingDescendantsIntoOneNode;
|
|
||||||
bool _isMergingDescendantsIntoOneNode = false;
|
|
||||||
set isMergingDescendantsIntoOneNode(bool value) {
|
|
||||||
assert(isSemanticBoundary);
|
|
||||||
_isMergingDescendantsIntoOneNode = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SEMANTIC ANNOTATIONS
|
// SEMANTIC ANNOTATIONS
|
||||||
// These will end up on [SemanticNode]s generated from
|
// These will end up on [SemanticNode]s generated from
|
||||||
// [SemanticsConfiguration]s.
|
// [SemanticsConfiguration]s.
|
||||||
@ -1645,9 +1633,12 @@ class SemanticsConfiguration {
|
|||||||
/// If set to true, the descendants of the owning [RenderObject]'s
|
/// If set to true, the descendants of the owning [RenderObject]'s
|
||||||
/// [SemanticsNode] will merge their semantic information into the
|
/// [SemanticsNode] will merge their semantic information into the
|
||||||
/// [SemanticsNode] representing the owning [RenderObject].
|
/// [SemanticsNode] representing the owning [RenderObject].
|
||||||
|
///
|
||||||
|
/// Setting this to true requires that [isSemanticBoundary] is also true.
|
||||||
bool get isMergingSemanticsOfDescendants => _isMergingSemanticsOfDescendants;
|
bool get isMergingSemanticsOfDescendants => _isMergingSemanticsOfDescendants;
|
||||||
bool _isMergingSemanticsOfDescendants = false;
|
bool _isMergingSemanticsOfDescendants = false;
|
||||||
set isMergingSemanticsOfDescendants(bool value) {
|
set isMergingSemanticsOfDescendants(bool value) {
|
||||||
|
assert(isSemanticBoundary);
|
||||||
_isMergingSemanticsOfDescendants = value;
|
_isMergingSemanticsOfDescendants = value;
|
||||||
_hasBeenAnnotated = true;
|
_hasBeenAnnotated = true;
|
||||||
}
|
}
|
||||||
@ -1910,9 +1901,11 @@ class SemanticsConfiguration {
|
|||||||
/// Returns an exact copy of this configuration.
|
/// Returns an exact copy of this configuration.
|
||||||
SemanticsConfiguration copy() {
|
SemanticsConfiguration copy() {
|
||||||
return new SemanticsConfiguration()
|
return new SemanticsConfiguration()
|
||||||
..isSemanticBoundary = isSemanticBoundary
|
.._isSemanticBoundary = _isSemanticBoundary
|
||||||
..explicitChildNodes = explicitChildNodes
|
..explicitChildNodes = explicitChildNodes
|
||||||
|
..isBlockingSemanticsOfPreviouslyPaintedNodes = isBlockingSemanticsOfPreviouslyPaintedNodes
|
||||||
.._hasBeenAnnotated = _hasBeenAnnotated
|
.._hasBeenAnnotated = _hasBeenAnnotated
|
||||||
|
.._isMergingSemanticsOfDescendants = _isMergingSemanticsOfDescendants
|
||||||
.._textDirection = _textDirection
|
.._textDirection = _textDirection
|
||||||
.._label = _label
|
.._label = _label
|
||||||
.._increasedValue = _increasedValue
|
.._increasedValue = _increasedValue
|
||||||
@ -1920,6 +1913,7 @@ class SemanticsConfiguration {
|
|||||||
.._decreasedValue = _decreasedValue
|
.._decreasedValue = _decreasedValue
|
||||||
.._hint = _hint
|
.._hint = _hint
|
||||||
.._flags = _flags
|
.._flags = _flags
|
||||||
|
.._tagsForChildren = _tagsForChildren
|
||||||
.._actionsAsBits = _actionsAsBits
|
.._actionsAsBits = _actionsAsBits
|
||||||
.._actions.addAll(_actions);
|
.._actions.addAll(_actions);
|
||||||
}
|
}
|
||||||
|
@ -570,21 +570,6 @@ class RawGestureDetectorState extends State<RawGestureDetector> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a [SemanticsEvent] in the context of the [SemanticsNode] that is
|
|
||||||
/// annotated with this object's semantics information.
|
|
||||||
///
|
|
||||||
/// The event can be interpreted by assistive technologies to provide
|
|
||||||
/// additional feedback to the user about the state of the UI.
|
|
||||||
///
|
|
||||||
/// The event will not be sent if [RawGestureDetector.excludeFromSemantics] is
|
|
||||||
/// set to true.
|
|
||||||
void sendSemanticsEvent(SemanticsEvent event) {
|
|
||||||
if (!widget.excludeFromSemantics) {
|
|
||||||
final RenderSemanticsGestureHandler semanticsGestureHandler = context.findRenderObject();
|
|
||||||
semanticsGestureHandler.sendSemanticsEvent(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
for (GestureRecognizer recognizer in _recognizers.values)
|
for (GestureRecognizer recognizer in _recognizers.values)
|
||||||
|
@ -281,7 +281,8 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin
|
|||||||
if (_semanticsScrollEventScheduled)
|
if (_semanticsScrollEventScheduled)
|
||||||
return;
|
return;
|
||||||
SchedulerBinding.instance.addPostFrameCallback((Duration timestamp) {
|
SchedulerBinding.instance.addPostFrameCallback((Duration timestamp) {
|
||||||
_gestureDetectorKey.currentState?.sendSemanticsEvent(new ScrollCompletedSemanticsEvent(
|
final _RenderExcludableScrollSemantics render = _excludableScrollSemanticsKey.currentContext?.findRenderObject();
|
||||||
|
render?.sendSemanticsEvent(new ScrollCompletedSemanticsEvent(
|
||||||
axis: position.axis,
|
axis: position.axis,
|
||||||
pixels: position.pixels,
|
pixels: position.pixels,
|
||||||
minScrollExtent: position.minScrollExtent,
|
minScrollExtent: position.minScrollExtent,
|
||||||
@ -332,7 +333,9 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// SEMANTICS ACTIONS
|
// SEMANTICS
|
||||||
|
|
||||||
|
final GlobalKey _excludableScrollSemanticsKey = new GlobalKey();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@protected
|
@protected
|
||||||
@ -487,18 +490,24 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
assert(position != null);
|
assert(position != null);
|
||||||
// TODO(ianh): Having all these global keys is sad.
|
// TODO(ianh): Having all these global keys is sad.
|
||||||
final Widget result = new RawGestureDetector(
|
final Widget result = new _ExcludableScrollSemantics(
|
||||||
key: _gestureDetectorKey,
|
key: _excludableScrollSemanticsKey,
|
||||||
gestures: _gestureRecognizers,
|
child: new RawGestureDetector(
|
||||||
behavior: HitTestBehavior.opaque,
|
key: _gestureDetectorKey,
|
||||||
child: new IgnorePointer(
|
gestures: _gestureRecognizers,
|
||||||
key: _ignorePointerKey,
|
behavior: HitTestBehavior.opaque,
|
||||||
ignoring: _shouldIgnorePointer,
|
child: new Semantics(
|
||||||
ignoringSemantics: false,
|
explicitChildNodes: true,
|
||||||
child: new _ScrollableScope(
|
child: new IgnorePointer(
|
||||||
scrollable: this,
|
key: _ignorePointerKey,
|
||||||
position: position,
|
ignoring: _shouldIgnorePointer,
|
||||||
child: widget.viewportBuilder(context, position),
|
ignoringSemantics: false,
|
||||||
|
child: new _ScrollableScope(
|
||||||
|
scrollable: this,
|
||||||
|
position: position,
|
||||||
|
child: widget.viewportBuilder(context, position),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -511,3 +520,70 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin
|
|||||||
description.add(new DiagnosticsProperty<ScrollPosition>('position', position));
|
description.add(new DiagnosticsProperty<ScrollPosition>('position', position));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// With [_ExcludableScrollSemantics] certain child [SemanticsNode]s can be
|
||||||
|
/// excluded from the scrollable area for semantics purposes.
|
||||||
|
///
|
||||||
|
/// Nodes, that are to be excluded, have to be tagged with
|
||||||
|
/// [RenderViewport.excludeFromScrolling] and the [RenderAbstractViewport] in
|
||||||
|
/// use has to add the [RenderViewport.useTwoPaneSemantics] tag to its
|
||||||
|
/// [SemanticsConfiguration] by overriding
|
||||||
|
/// [RenderObject.describeSemanticsConfiguration].
|
||||||
|
///
|
||||||
|
/// If the tag [RenderViewport.useTwoPaneSemantics] is present on the viewport,
|
||||||
|
/// two semantics nodes will be used to represent the [Scrollable]: The outer
|
||||||
|
/// node will contain all children, that are excluded from scrolling. The inner
|
||||||
|
/// node, which is annotated with the scrolling actions, will house the
|
||||||
|
/// scrollable children.
|
||||||
|
class _ExcludableScrollSemantics extends SingleChildRenderObjectWidget {
|
||||||
|
const _ExcludableScrollSemantics({ Key key, Widget child }) : super(key: key, child: child);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_RenderExcludableScrollSemantics createRenderObject(BuildContext context) => new _RenderExcludableScrollSemantics();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _RenderExcludableScrollSemantics extends RenderProxyBox {
|
||||||
|
_RenderExcludableScrollSemantics({ RenderBox child }) : super(child);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
||||||
|
super.describeSemanticsConfiguration(config);
|
||||||
|
config.isSemanticBoundary = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SemanticsNode _innerNode;
|
||||||
|
SemanticsNode _annotatedNode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void assembleSemanticsNode(SemanticsNode node, SemanticsConfiguration config, Iterable<SemanticsNode> children) {
|
||||||
|
if (children.isEmpty || !children.first.isTagged(RenderViewport.useTwoPaneSemantics)) {
|
||||||
|
_annotatedNode = node;
|
||||||
|
super.assembleSemanticsNode(node, config, children);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_innerNode ??= new SemanticsNode(showOnScreen: showOnScreen);
|
||||||
|
_innerNode
|
||||||
|
..isMergedIntoParent = node.isPartOfNodeMerging
|
||||||
|
..rect = Offset.zero & node.rect.size;
|
||||||
|
_annotatedNode = _innerNode;
|
||||||
|
|
||||||
|
final List<SemanticsNode> excluded = <SemanticsNode>[_innerNode];
|
||||||
|
final List<SemanticsNode> included = <SemanticsNode>[];
|
||||||
|
for (SemanticsNode child in children) {
|
||||||
|
assert(child.isTagged(RenderViewport.useTwoPaneSemantics));
|
||||||
|
if (child.isTagged(RenderViewport.excludeFromScrolling))
|
||||||
|
excluded.add(child);
|
||||||
|
else
|
||||||
|
included.add(child);
|
||||||
|
}
|
||||||
|
node.updateWith(config: null, childrenInInversePaintOrder: excluded);
|
||||||
|
_innerNode.updateWith(config: config, childrenInInversePaintOrder: included);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sends a [SemanticsEvent] in the context of the [SemanticsNode] that is
|
||||||
|
/// annotated with this object's semantics information.
|
||||||
|
void sendSemanticsEvent(SemanticsEvent event) {
|
||||||
|
_annotatedNode?.sendEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -13,6 +13,10 @@ import '../rendering/mock_canvas.dart';
|
|||||||
import '../widgets/semantics_tester.dart';
|
import '../widgets/semantics_tester.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
setUp(() {
|
||||||
|
debugResetSemanticsIdCounter();
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('Does FlatButton contribute semantics', (WidgetTester tester) async {
|
testWidgets('Does FlatButton contribute semantics', (WidgetTester tester) async {
|
||||||
final SemanticsTester semantics = new SemanticsTester(tester);
|
final SemanticsTester semantics = new SemanticsTester(tester);
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
@ -33,11 +37,17 @@ void main() {
|
|||||||
new TestSemantics.root(
|
new TestSemantics.root(
|
||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics.rootChild(
|
new TestSemantics.rootChild(
|
||||||
actions: SemanticsAction.tap.index,
|
actions: <SemanticsAction>[
|
||||||
|
SemanticsAction.tap,
|
||||||
|
],
|
||||||
label: 'ABC',
|
label: 'ABC',
|
||||||
rect: new Rect.fromLTRB(0.0, 0.0, 88.0, 36.0),
|
rect: new Rect.fromLTRB(0.0, 0.0, 88.0, 36.0),
|
||||||
transform: new Matrix4.translationValues(356.0, 282.0, 0.0),
|
transform: new Matrix4.translationValues(356.0, 282.0, 0.0),
|
||||||
flags: SemanticsFlag.isButton.index,
|
flags: <SemanticsFlag>[
|
||||||
|
SemanticsFlag.isButton,
|
||||||
|
SemanticsFlag.hasEnabledState,
|
||||||
|
SemanticsFlag.isEnabled,
|
||||||
|
],
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -67,11 +77,17 @@ void main() {
|
|||||||
new TestSemantics.root(
|
new TestSemantics.root(
|
||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics.rootChild(
|
new TestSemantics.rootChild(
|
||||||
actions: SemanticsAction.tap.index,
|
actions: <SemanticsAction>[
|
||||||
|
SemanticsAction.tap,
|
||||||
|
],
|
||||||
label: 'ABC',
|
label: 'ABC',
|
||||||
rect: new Rect.fromLTRB(0.0, 0.0, 88.0, 36.0),
|
rect: new Rect.fromLTRB(0.0, 0.0, 88.0, 36.0),
|
||||||
transform: new Matrix4.translationValues(356.0, 282.0, 0.0),
|
transform: new Matrix4.translationValues(356.0, 282.0, 0.0),
|
||||||
flags: SemanticsFlag.isButton.index,
|
flags: <SemanticsFlag>[
|
||||||
|
SemanticsFlag.isButton,
|
||||||
|
SemanticsFlag.hasEnabledState,
|
||||||
|
SemanticsFlag.isEnabled,
|
||||||
|
],
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
@ -248,4 +264,83 @@ void main() {
|
|||||||
await gesture.up();
|
await gesture.up();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Disabled MaterialButton has same semantic size as enabled and exposes disabled semantics', (WidgetTester tester) async {
|
||||||
|
final SemanticsTester semantics = new SemanticsTester(tester);
|
||||||
|
|
||||||
|
final Rect expectedButtonSize = new Rect.fromLTRB(0.0, 0.0, 116.0, 36.0);
|
||||||
|
// Button is in center of screen
|
||||||
|
final Matrix4 expectedButtonTransform = new Matrix4.identity()
|
||||||
|
..translate(
|
||||||
|
TestSemantics.fullScreen.width / 2 - expectedButtonSize.width /2,
|
||||||
|
TestSemantics.fullScreen.height / 2 - expectedButtonSize.height /2,
|
||||||
|
);
|
||||||
|
|
||||||
|
// enabled button
|
||||||
|
await tester.pumpWidget(new Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: new Material(
|
||||||
|
child: new Center(
|
||||||
|
child: new MaterialButton(
|
||||||
|
child: const Text('Button'),
|
||||||
|
onPressed: () { /* to make sure the button is enabled */ },
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(semantics, hasSemantics(
|
||||||
|
new TestSemantics.root(
|
||||||
|
children: <TestSemantics>[
|
||||||
|
new TestSemantics.rootChild(
|
||||||
|
id: 1,
|
||||||
|
rect: expectedButtonSize,
|
||||||
|
transform: expectedButtonTransform,
|
||||||
|
label: 'Button',
|
||||||
|
actions: <SemanticsAction>[
|
||||||
|
SemanticsAction.tap,
|
||||||
|
],
|
||||||
|
flags: <SemanticsFlag>[
|
||||||
|
SemanticsFlag.isButton,
|
||||||
|
SemanticsFlag.hasEnabledState,
|
||||||
|
SemanticsFlag.isEnabled,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
// disabled button
|
||||||
|
await tester.pumpWidget(const Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: const Material(
|
||||||
|
child: const Center(
|
||||||
|
child: const MaterialButton(
|
||||||
|
child: const Text('Button'),
|
||||||
|
onPressed: null, // button is disabled
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(semantics, hasSemantics(
|
||||||
|
new TestSemantics.root(
|
||||||
|
children: <TestSemantics>[
|
||||||
|
new TestSemantics.rootChild(
|
||||||
|
id: 1,
|
||||||
|
rect: expectedButtonSize,
|
||||||
|
transform: expectedButtonTransform,
|
||||||
|
label: 'Button',
|
||||||
|
flags: <SemanticsFlag>[
|
||||||
|
SemanticsFlag.isButton,
|
||||||
|
SemanticsFlag.hasEnabledState,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
|
||||||
|
semantics.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -48,8 +48,14 @@ void main() {
|
|||||||
id: 2,
|
id: 2,
|
||||||
label: 'Button',
|
label: 'Button',
|
||||||
textDirection: TextDirection.ltr,
|
textDirection: TextDirection.ltr,
|
||||||
actions: SemanticsAction.tap.index,
|
actions: <SemanticsAction>[
|
||||||
flags: SemanticsFlag.isButton.index,
|
SemanticsAction.tap,
|
||||||
|
],
|
||||||
|
flags: <SemanticsFlag>[
|
||||||
|
SemanticsFlag.isButton,
|
||||||
|
SemanticsFlag.hasEnabledState,
|
||||||
|
SemanticsFlag.isEnabled,
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -94,11 +94,11 @@ void main() {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
||||||
// This test verifies that the label and the control get merged.
|
// This test verifies that the label and the control get merged.
|
||||||
expect(semantics, hasSemantics(new TestSemantics.root(
|
expect(semantics, hasSemantics(new TestSemantics.root(
|
||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics.rootChild(
|
new TestSemantics.rootChild(
|
||||||
id: 1,
|
|
||||||
rect: new Rect.fromLTWH(0.0, 0.0, 800.0, 56.0),
|
rect: new Rect.fromLTWH(0.0, 0.0, 800.0, 56.0),
|
||||||
transform: null,
|
transform: null,
|
||||||
flags: <SemanticsFlag>[
|
flags: <SemanticsFlag>[
|
||||||
@ -111,7 +111,6 @@ void main() {
|
|||||||
label: 'aaa\nAAA',
|
label: 'aaa\nAAA',
|
||||||
),
|
),
|
||||||
new TestSemantics.rootChild(
|
new TestSemantics.rootChild(
|
||||||
id: 4,
|
|
||||||
rect: new Rect.fromLTWH(0.0, 0.0, 800.0, 56.0),
|
rect: new Rect.fromLTWH(0.0, 0.0, 800.0, 56.0),
|
||||||
transform: new Matrix4.translationValues(0.0, 56.0, 0.0),
|
transform: new Matrix4.translationValues(0.0, 56.0, 0.0),
|
||||||
flags: <SemanticsFlag>[
|
flags: <SemanticsFlag>[
|
||||||
@ -124,7 +123,6 @@ void main() {
|
|||||||
label: 'bbb\nBBB',
|
label: 'bbb\nBBB',
|
||||||
),
|
),
|
||||||
new TestSemantics.rootChild(
|
new TestSemantics.rootChild(
|
||||||
id: 7,
|
|
||||||
rect: new Rect.fromLTWH(0.0, 0.0, 800.0, 56.0),
|
rect: new Rect.fromLTWH(0.0, 0.0, 800.0, 56.0),
|
||||||
transform: new Matrix4.translationValues(0.0, 112.0, 0.0),
|
transform: new Matrix4.translationValues(0.0, 112.0, 0.0),
|
||||||
flags: <SemanticsFlag>[
|
flags: <SemanticsFlag>[
|
||||||
@ -136,7 +134,7 @@ void main() {
|
|||||||
label: 'CCC\nccc',
|
label: 'CCC\nccc',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)));
|
), ignoreId: true));
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -585,13 +585,21 @@ void _tests() {
|
|||||||
textDirection: TextDirection.ltr,
|
textDirection: TextDirection.ltr,
|
||||||
),
|
),
|
||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
flags: <SemanticsFlag>[SemanticsFlag.isButton],
|
flags: <SemanticsFlag>[
|
||||||
|
SemanticsFlag.isButton,
|
||||||
|
SemanticsFlag.hasEnabledState,
|
||||||
|
SemanticsFlag.isEnabled,
|
||||||
|
],
|
||||||
actions: <SemanticsAction>[SemanticsAction.tap],
|
actions: <SemanticsAction>[SemanticsAction.tap],
|
||||||
label: r'CANCEL',
|
label: r'CANCEL',
|
||||||
textDirection: TextDirection.ltr,
|
textDirection: TextDirection.ltr,
|
||||||
),
|
),
|
||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
flags: <SemanticsFlag>[SemanticsFlag.isButton],
|
flags: <SemanticsFlag>[
|
||||||
|
SemanticsFlag.isButton,
|
||||||
|
SemanticsFlag.hasEnabledState,
|
||||||
|
SemanticsFlag.isEnabled,
|
||||||
|
],
|
||||||
actions: <SemanticsAction>[SemanticsAction.tap],
|
actions: <SemanticsAction>[SemanticsAction.tap],
|
||||||
label: r'OK',
|
label: r'OK',
|
||||||
textDirection: TextDirection.ltr,
|
textDirection: TextDirection.ltr,
|
||||||
|
@ -165,6 +165,10 @@ class TestScrollPhysics extends ScrollPhysics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
setUp(() {
|
||||||
|
debugResetSemanticsIdCounter();
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('TabBar tap selects tab', (WidgetTester tester) async {
|
testWidgets('TabBar tap selects tab', (WidgetTester tester) async {
|
||||||
final List<String> tabs = <String>['A', 'B', 'C'];
|
final List<String> tabs = <String>['A', 'B', 'C'];
|
||||||
|
|
||||||
@ -1213,19 +1217,25 @@ void main() {
|
|||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
id: 2,
|
id: 2,
|
||||||
actions: SemanticsAction.tap.index,
|
rect: TestSemantics.fullScreen,
|
||||||
flags: SemanticsFlag.isSelected.index,
|
children: <TestSemantics>[
|
||||||
label: 'TAB #0\nTab 1 of 2',
|
new TestSemantics(
|
||||||
rect: new Rect.fromLTRB(0.0, 0.0, 108.0, kTextTabBarHeight),
|
id: 3,
|
||||||
transform: new Matrix4.translationValues(0.0, 276.0, 0.0),
|
actions: SemanticsAction.tap.index,
|
||||||
),
|
flags: SemanticsFlag.isSelected.index,
|
||||||
new TestSemantics(
|
label: 'TAB #0\nTab 1 of 2',
|
||||||
id: 3,
|
rect: new Rect.fromLTRB(0.0, 0.0, 108.0, kTextTabBarHeight),
|
||||||
actions: SemanticsAction.tap.index,
|
transform: new Matrix4.translationValues(0.0, 276.0, 0.0),
|
||||||
label: 'TAB #1\nTab 2 of 2',
|
),
|
||||||
rect: new Rect.fromLTRB(0.0, 0.0, 108.0, kTextTabBarHeight),
|
new TestSemantics(
|
||||||
transform: new Matrix4.translationValues(108.0, 276.0, 0.0),
|
id: 4,
|
||||||
),
|
actions: SemanticsAction.tap.index,
|
||||||
|
label: 'TAB #1\nTab 2 of 2',
|
||||||
|
rect: new Rect.fromLTRB(0.0, 0.0, 108.0, kTextTabBarHeight),
|
||||||
|
transform: new Matrix4.translationValues(108.0, 276.0, 0.0),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -1458,24 +1468,30 @@ void main() {
|
|||||||
final TestSemantics expectedSemantics = new TestSemantics.root(
|
final TestSemantics expectedSemantics = new TestSemantics.root(
|
||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics.rootChild(
|
new TestSemantics.rootChild(
|
||||||
id: 23,
|
id: 1,
|
||||||
rect: TestSemantics.fullScreen,
|
rect: TestSemantics.fullScreen,
|
||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
id: 24,
|
id: 2,
|
||||||
actions: SemanticsAction.tap.index,
|
rect: TestSemantics.fullScreen,
|
||||||
flags: SemanticsFlag.isSelected.index,
|
children: <TestSemantics>[
|
||||||
label: 'Semantics override 0\nTab 1 of 2',
|
new TestSemantics(
|
||||||
rect: new Rect.fromLTRB(0.0, 0.0, 108.0, kTextTabBarHeight),
|
id: 3,
|
||||||
transform: new Matrix4.translationValues(0.0, 276.0, 0.0),
|
actions: SemanticsAction.tap.index,
|
||||||
),
|
flags: SemanticsFlag.isSelected.index,
|
||||||
new TestSemantics(
|
label: 'Semantics override 0\nTab 1 of 2',
|
||||||
id: 25,
|
rect: new Rect.fromLTRB(0.0, 0.0, 108.0, kTextTabBarHeight),
|
||||||
actions: SemanticsAction.tap.index,
|
transform: new Matrix4.translationValues(0.0, 276.0, 0.0),
|
||||||
label: 'Semantics override 1\nTab 2 of 2',
|
),
|
||||||
rect: new Rect.fromLTRB(0.0, 0.0, 108.0, kTextTabBarHeight),
|
new TestSemantics(
|
||||||
transform: new Matrix4.translationValues(108.0, 276.0, 0.0),
|
id: 4,
|
||||||
),
|
actions: SemanticsAction.tap.index,
|
||||||
|
label: 'Semantics override 1\nTab 2 of 2',
|
||||||
|
rect: new Rect.fromLTRB(0.0, 0.0, 108.0, kTextTabBarHeight),
|
||||||
|
transform: new Matrix4.translationValues(108.0, 276.0, 0.0),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -11,6 +11,10 @@ import '../rendering/rendering_tester.dart';
|
|||||||
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
setUp(() {
|
||||||
|
debugResetSemanticsIdCounter();
|
||||||
|
});
|
||||||
|
|
||||||
group('SemanticsNode', () {
|
group('SemanticsNode', () {
|
||||||
const SemanticsTag tag1 = const SemanticsTag('Tag One');
|
const SemanticsTag tag1 = const SemanticsTag('Tag One');
|
||||||
const SemanticsTag tag2 = const SemanticsTag('Tag Two');
|
const SemanticsTag tag2 = const SemanticsTag('Tag Two');
|
||||||
@ -45,6 +49,7 @@ void main() {
|
|||||||
tags.add(tag3);
|
tags.add(tag3);
|
||||||
|
|
||||||
final SemanticsConfiguration config = new SemanticsConfiguration()
|
final SemanticsConfiguration config = new SemanticsConfiguration()
|
||||||
|
..isSemanticBoundary = true
|
||||||
..isMergingSemanticsOfDescendants = true;
|
..isMergingSemanticsOfDescendants = true;
|
||||||
|
|
||||||
node.updateWith(
|
node.updateWith(
|
||||||
@ -121,9 +126,9 @@ void main() {
|
|||||||
|
|
||||||
expect(
|
expect(
|
||||||
root.toStringDeep(childOrder: DebugSemanticsDumpOrder.traversal),
|
root.toStringDeep(childOrder: DebugSemanticsDumpOrder.traversal),
|
||||||
'SemanticsNode#8(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 10.0, 5.0))\n'
|
'SemanticsNode#3(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 10.0, 5.0))\n'
|
||||||
'├SemanticsNode#6(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 5.0, 5.0))\n'
|
'├SemanticsNode#1(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 5.0, 5.0))\n'
|
||||||
'└SemanticsNode#7(STALE, owner: null, Rect.fromLTRB(5.0, 0.0, 10.0, 5.0))\n',
|
'└SemanticsNode#2(STALE, owner: null, Rect.fromLTRB(5.0, 0.0, 10.0, 5.0))\n',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -140,16 +145,16 @@ void main() {
|
|||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
root.toStringDeep(childOrder: DebugSemanticsDumpOrder.traversal),
|
root.toStringDeep(childOrder: DebugSemanticsDumpOrder.traversal),
|
||||||
'SemanticsNode#11(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 20.0, 5.0))\n'
|
'SemanticsNode#3(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 20.0, 5.0))\n'
|
||||||
'├SemanticsNode#10(STALE, owner: null, Rect.fromLTRB(10.0, 0.0, 15.0, 5.0))\n'
|
'├SemanticsNode#2(STALE, owner: null, Rect.fromLTRB(10.0, 0.0, 15.0, 5.0))\n'
|
||||||
'└SemanticsNode#9(STALE, owner: null, Rect.fromLTRB(15.0, 0.0, 20.0, 5.0))\n',
|
'└SemanticsNode#1(STALE, owner: null, Rect.fromLTRB(15.0, 0.0, 20.0, 5.0))\n',
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
root.toStringDeep(childOrder: DebugSemanticsDumpOrder.inverseHitTest),
|
root.toStringDeep(childOrder: DebugSemanticsDumpOrder.inverseHitTest),
|
||||||
'SemanticsNode#11(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 20.0, 5.0))\n'
|
'SemanticsNode#3(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 20.0, 5.0))\n'
|
||||||
'├SemanticsNode#9(STALE, owner: null, Rect.fromLTRB(15.0, 0.0, 20.0, 5.0))\n'
|
'├SemanticsNode#1(STALE, owner: null, Rect.fromLTRB(15.0, 0.0, 20.0, 5.0))\n'
|
||||||
'└SemanticsNode#10(STALE, owner: null, Rect.fromLTRB(10.0, 0.0, 15.0, 5.0))\n',
|
'└SemanticsNode#2(STALE, owner: null, Rect.fromLTRB(10.0, 0.0, 15.0, 5.0))\n',
|
||||||
);
|
);
|
||||||
|
|
||||||
final SemanticsNode child3 = new SemanticsNode()
|
final SemanticsNode child3 = new SemanticsNode()
|
||||||
@ -173,22 +178,22 @@ void main() {
|
|||||||
|
|
||||||
expect(
|
expect(
|
||||||
rootComplex.toStringDeep(childOrder: DebugSemanticsDumpOrder.traversal),
|
rootComplex.toStringDeep(childOrder: DebugSemanticsDumpOrder.traversal),
|
||||||
'SemanticsNode#15(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 25.0, 5.0))\n'
|
'SemanticsNode#7(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 25.0, 5.0))\n'
|
||||||
'├SemanticsNode#12(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 10.0, 5.0))\n'
|
'├SemanticsNode#4(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 10.0, 5.0))\n'
|
||||||
'│├SemanticsNode#14(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 5.0, 5.0))\n'
|
'│├SemanticsNode#6(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 5.0, 5.0))\n'
|
||||||
'│└SemanticsNode#13(STALE, owner: null, Rect.fromLTRB(5.0, 0.0, 10.0, 5.0))\n'
|
'│└SemanticsNode#5(STALE, owner: null, Rect.fromLTRB(5.0, 0.0, 10.0, 5.0))\n'
|
||||||
'├SemanticsNode#10(STALE, owner: null, Rect.fromLTRB(10.0, 0.0, 15.0, 5.0))\n'
|
'├SemanticsNode#2(STALE, owner: null, Rect.fromLTRB(10.0, 0.0, 15.0, 5.0))\n'
|
||||||
'└SemanticsNode#9(STALE, owner: null, Rect.fromLTRB(15.0, 0.0, 20.0, 5.0))\n',
|
'└SemanticsNode#1(STALE, owner: null, Rect.fromLTRB(15.0, 0.0, 20.0, 5.0))\n',
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
rootComplex.toStringDeep(childOrder: DebugSemanticsDumpOrder.inverseHitTest),
|
rootComplex.toStringDeep(childOrder: DebugSemanticsDumpOrder.inverseHitTest),
|
||||||
'SemanticsNode#15(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 25.0, 5.0))\n'
|
'SemanticsNode#7(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 25.0, 5.0))\n'
|
||||||
'├SemanticsNode#9(STALE, owner: null, Rect.fromLTRB(15.0, 0.0, 20.0, 5.0))\n'
|
'├SemanticsNode#1(STALE, owner: null, Rect.fromLTRB(15.0, 0.0, 20.0, 5.0))\n'
|
||||||
'├SemanticsNode#10(STALE, owner: null, Rect.fromLTRB(10.0, 0.0, 15.0, 5.0))\n'
|
'├SemanticsNode#2(STALE, owner: null, Rect.fromLTRB(10.0, 0.0, 15.0, 5.0))\n'
|
||||||
'└SemanticsNode#12(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 10.0, 5.0))\n'
|
'└SemanticsNode#4(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 10.0, 5.0))\n'
|
||||||
' ├SemanticsNode#13(STALE, owner: null, Rect.fromLTRB(5.0, 0.0, 10.0, 5.0))\n'
|
' ├SemanticsNode#5(STALE, owner: null, Rect.fromLTRB(5.0, 0.0, 10.0, 5.0))\n'
|
||||||
' └SemanticsNode#14(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 5.0, 5.0))\n',
|
' └SemanticsNode#6(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 5.0, 5.0))\n',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -196,15 +201,16 @@ void main() {
|
|||||||
final SemanticsNode minimalProperties = new SemanticsNode();
|
final SemanticsNode minimalProperties = new SemanticsNode();
|
||||||
expect(
|
expect(
|
||||||
minimalProperties.toStringDeep(),
|
minimalProperties.toStringDeep(),
|
||||||
'SemanticsNode#16(Rect.fromLTRB(0.0, 0.0, 0.0, 0.0))\n',
|
'SemanticsNode#1(Rect.fromLTRB(0.0, 0.0, 0.0, 0.0))\n',
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
minimalProperties.toStringDeep(minLevel: DiagnosticLevel.hidden),
|
minimalProperties.toStringDeep(minLevel: DiagnosticLevel.hidden),
|
||||||
'SemanticsNode#16(owner: null, isPartOfNodeMerging: false, Rect.fromLTRB(0.0, 0.0, 0.0, 0.0), actions: [], isSelected: false, isFocused: false, isButton: false, isTextField: false, label: "", value: "", increasedValue: "", decreasedValue: "", hint: "", textDirection: null)\n'
|
'SemanticsNode#1(owner: null, isMergedIntoParent: false, mergeAllDescendantsIntoThisNode: false, Rect.fromLTRB(0.0, 0.0, 0.0, 0.0), actions: [], isSelected: false, isFocused: false, isButton: false, isTextField: false, label: "", value: "", increasedValue: "", decreasedValue: "", hint: "", textDirection: null)\n'
|
||||||
);
|
);
|
||||||
|
|
||||||
final SemanticsConfiguration config = new SemanticsConfiguration()
|
final SemanticsConfiguration config = new SemanticsConfiguration()
|
||||||
|
..isSemanticBoundary = true
|
||||||
..isMergingSemanticsOfDescendants = true
|
..isMergingSemanticsOfDescendants = true
|
||||||
..onScrollUp = () { }
|
..onScrollUp = () { }
|
||||||
..onLongPress = () { }
|
..onLongPress = () { }
|
||||||
@ -220,7 +226,7 @@ void main() {
|
|||||||
..updateWith(config: config, childrenInInversePaintOrder: null);
|
..updateWith(config: config, childrenInInversePaintOrder: null);
|
||||||
expect(
|
expect(
|
||||||
allProperties.toStringDeep(),
|
allProperties.toStringDeep(),
|
||||||
'SemanticsNode#17(STALE, owner: null, leaf merge, Rect.fromLTRB(60.0, 20.0, 80.0, 50.0), actions: [longPress, scrollUp, showOnScreen], unchecked, selected, button, label: "Use all the properties", textDirection: rtl)\n',
|
'SemanticsNode#2(STALE, owner: null, merge boundary ⛔️, Rect.fromLTRB(60.0, 20.0, 80.0, 50.0), actions: [longPress, scrollUp, showOnScreen], unchecked, selected, button, label: "Use all the properties", textDirection: rtl)\n',
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
allProperties.getSemanticsData().toString(),
|
allProperties.getSemanticsData().toString(),
|
||||||
@ -232,7 +238,7 @@ void main() {
|
|||||||
..transform = new Matrix4.diagonal3(new Vector3(10.0, 10.0, 1.0));
|
..transform = new Matrix4.diagonal3(new Vector3(10.0, 10.0, 1.0));
|
||||||
expect(
|
expect(
|
||||||
scaled.toStringDeep(),
|
scaled.toStringDeep(),
|
||||||
'SemanticsNode#18(STALE, owner: null, Rect.fromLTRB(50.0, 10.0, 70.0, 40.0) scaled by 10.0x)\n',
|
'SemanticsNode#3(STALE, owner: null, Rect.fromLTRB(50.0, 10.0, 70.0, 40.0) scaled by 10.0x)\n',
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
scaled.getSemanticsData().toString(),
|
scaled.getSemanticsData().toString(),
|
||||||
@ -251,7 +257,6 @@ void main() {
|
|||||||
expect(config.isSelected, isFalse);
|
expect(config.isSelected, isFalse);
|
||||||
expect(config.isBlockingSemanticsOfPreviouslyPaintedNodes, isFalse);
|
expect(config.isBlockingSemanticsOfPreviouslyPaintedNodes, isFalse);
|
||||||
expect(config.isFocused, isFalse);
|
expect(config.isFocused, isFalse);
|
||||||
expect(config.isMergingDescendantsIntoOneNode, isFalse);
|
|
||||||
expect(config.isTextField, isFalse);
|
expect(config.isTextField, isFalse);
|
||||||
|
|
||||||
expect(config.onShowOnScreen, isNull);
|
expect(config.onShowOnScreen, isNull);
|
||||||
@ -274,7 +279,6 @@ void main() {
|
|||||||
config.isSelected = true;
|
config.isSelected = true;
|
||||||
config.isBlockingSemanticsOfPreviouslyPaintedNodes = true;
|
config.isBlockingSemanticsOfPreviouslyPaintedNodes = true;
|
||||||
config.isFocused = true;
|
config.isFocused = true;
|
||||||
config.isMergingDescendantsIntoOneNode = true;
|
|
||||||
config.isTextField = true;
|
config.isTextField = true;
|
||||||
|
|
||||||
final VoidCallback onShowOnScreen = () { };
|
final VoidCallback onShowOnScreen = () { };
|
||||||
@ -309,7 +313,6 @@ void main() {
|
|||||||
expect(config.isSelected, isTrue);
|
expect(config.isSelected, isTrue);
|
||||||
expect(config.isBlockingSemanticsOfPreviouslyPaintedNodes, isTrue);
|
expect(config.isBlockingSemanticsOfPreviouslyPaintedNodes, isTrue);
|
||||||
expect(config.isFocused, isTrue);
|
expect(config.isFocused, isTrue);
|
||||||
expect(config.isMergingDescendantsIntoOneNode, isTrue);
|
|
||||||
expect(config.isTextField, isTrue);
|
expect(config.isTextField, isTrue);
|
||||||
|
|
||||||
expect(config.onShowOnScreen, same(onShowOnScreen));
|
expect(config.onShowOnScreen, same(onShowOnScreen));
|
||||||
|
@ -220,73 +220,84 @@ void main() {
|
|||||||
' │ diagnosis: insufficient data to draw conclusion (less than five\n'
|
' │ diagnosis: insufficient data to draw conclusion (less than five\n'
|
||||||
' │ repaints)\n'
|
' │ repaints)\n'
|
||||||
' │\n'
|
' │\n'
|
||||||
' └─child: RenderSemanticsGestureHandler#00000\n'
|
' └─child: _RenderExcludableScrollSemantics#00000\n'
|
||||||
' │ parentData: <none> (can use size)\n'
|
' │ parentData: <none> (can use size)\n'
|
||||||
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
||||||
|
' │ semantic boundary\n'
|
||||||
' │ size: Size(800.0, 600.0)\n'
|
' │ size: Size(800.0, 600.0)\n'
|
||||||
' │ gestures: vertical scroll\n'
|
|
||||||
' │\n'
|
' │\n'
|
||||||
' └─child: RenderPointerListener#00000\n'
|
' └─child: RenderSemanticsGestureHandler#00000\n'
|
||||||
' │ parentData: <none> (can use size)\n'
|
' │ parentData: <none> (can use size)\n'
|
||||||
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
||||||
' │ size: Size(800.0, 600.0)\n'
|
' │ size: Size(800.0, 600.0)\n'
|
||||||
' │ behavior: opaque\n'
|
' │ gestures: vertical scroll\n'
|
||||||
' │ listeners: down\n'
|
|
||||||
' │\n'
|
' │\n'
|
||||||
' └─child: RenderIgnorePointer#00000\n'
|
' └─child: RenderPointerListener#00000\n'
|
||||||
' │ parentData: <none> (can use size)\n'
|
' │ parentData: <none> (can use size)\n'
|
||||||
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
||||||
' │ size: Size(800.0, 600.0)\n'
|
' │ size: Size(800.0, 600.0)\n'
|
||||||
' │ ignoring: false\n'
|
' │ behavior: opaque\n'
|
||||||
' │ ignoringSemantics: false\n'
|
' │ listeners: down\n'
|
||||||
' │\n'
|
' │\n'
|
||||||
' └─child: RenderViewport#00000\n'
|
' └─child: RenderSemanticsAnnotations#00000\n'
|
||||||
' │ parentData: <none> (can use size)\n'
|
' │ parentData: <none> (can use size)\n'
|
||||||
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
||||||
' │ layer: OffsetLayer#00000\n'
|
|
||||||
' │ size: Size(800.0, 600.0)\n'
|
' │ size: Size(800.0, 600.0)\n'
|
||||||
' │ axisDirection: down\n'
|
|
||||||
' │ crossAxisDirection: right\n'
|
|
||||||
' │ offset: ScrollPositionWithSingleContext#00000(offset: 0.0, range:\n'
|
|
||||||
' │ 0.0..39400.0, viewport: 600.0, ScrollableState,\n'
|
|
||||||
' │ AlwaysScrollableScrollPhysics -> ClampingScrollPhysics,\n'
|
|
||||||
' │ IdleScrollActivity#00000, ScrollDirection.idle)\n'
|
|
||||||
' │ anchor: 0.0\n'
|
|
||||||
' │\n'
|
' │\n'
|
||||||
' └─center child: RenderSliverFixedExtentList#00000 relayoutBoundary=up1\n'
|
' └─child: RenderIgnorePointer#00000\n'
|
||||||
' │ parentData: paintOffset=Offset(0.0, 0.0) (can use size)\n'
|
' │ parentData: <none> (can use size)\n'
|
||||||
' │ constraints: SliverConstraints(AxisDirection.down,\n'
|
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
||||||
' │ GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n'
|
' │ size: Size(800.0, 600.0)\n'
|
||||||
' │ 0.0, remainingPaintExtent: 600.0, crossAxisExtent: 800.0,\n'
|
' │ ignoring: false\n'
|
||||||
' │ crossAxisDirection: AxisDirection.right,\n'
|
' │ ignoringSemantics: false\n'
|
||||||
' │ viewportMainAxisExtent: 600.0)\n'
|
|
||||||
' │ geometry: SliverGeometry(scrollExtent: 40000.0, paintExtent:\n'
|
|
||||||
' │ 600.0, maxPaintExtent: 40000.0, hasVisualOverflow: true)\n'
|
|
||||||
' │ currently live children: 0 to 1\n'
|
|
||||||
' │\n'
|
' │\n'
|
||||||
' ├─child with index 0: RenderLimitedBox#00000\n'
|
' └─child: RenderViewport#00000\n'
|
||||||
' │ │ parentData: index=0; layoutOffset=0.0\n'
|
' │ parentData: <none> (can use size)\n'
|
||||||
' │ │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
||||||
' │ │ size: Size(800.0, 400.0)\n'
|
' │ layer: OffsetLayer#00000\n'
|
||||||
' │ │ maxWidth: 400.0\n'
|
' │ size: Size(800.0, 600.0)\n'
|
||||||
' │ │ maxHeight: 400.0\n'
|
' │ axisDirection: down\n'
|
||||||
' │ │\n'
|
' │ crossAxisDirection: right\n'
|
||||||
' │ └─child: RenderCustomPaint#00000\n'
|
' │ offset: ScrollPositionWithSingleContext#00000(offset: 0.0, range:\n'
|
||||||
' │ parentData: <none> (can use size)\n'
|
' │ 0.0..39400.0, viewport: 600.0, ScrollableState,\n'
|
||||||
' │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
' │ AlwaysScrollableScrollPhysics -> ClampingScrollPhysics,\n'
|
||||||
' │ size: Size(800.0, 400.0)\n'
|
' │ IdleScrollActivity#00000, ScrollDirection.idle)\n'
|
||||||
' │\n'
|
' │ anchor: 0.0\n'
|
||||||
' └─child with index 1: RenderLimitedBox#00000\n' // <----- no dashed line starts here
|
|
||||||
' │ parentData: index=1; layoutOffset=400.0\n'
|
|
||||||
' │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
|
||||||
' │ size: Size(800.0, 400.0)\n'
|
|
||||||
' │ maxWidth: 400.0\n'
|
|
||||||
' │ maxHeight: 400.0\n'
|
|
||||||
' │\n'
|
' │\n'
|
||||||
' └─child: RenderCustomPaint#00000\n'
|
' └─center child: RenderSliverFixedExtentList#00000 relayoutBoundary=up1\n'
|
||||||
' parentData: <none> (can use size)\n'
|
' │ parentData: paintOffset=Offset(0.0, 0.0) (can use size)\n'
|
||||||
' constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
' │ constraints: SliverConstraints(AxisDirection.down,\n'
|
||||||
' size: Size(800.0, 400.0)\n'
|
' │ GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n'
|
||||||
|
' │ 0.0, remainingPaintExtent: 600.0, crossAxisExtent: 800.0,\n'
|
||||||
|
' │ crossAxisDirection: AxisDirection.right,\n'
|
||||||
|
' │ viewportMainAxisExtent: 600.0)\n'
|
||||||
|
' │ geometry: SliverGeometry(scrollExtent: 40000.0, paintExtent:\n'
|
||||||
|
' │ 600.0, maxPaintExtent: 40000.0, hasVisualOverflow: true)\n'
|
||||||
|
' │ currently live children: 0 to 1\n'
|
||||||
|
' │\n'
|
||||||
|
' ├─child with index 0: RenderLimitedBox#00000\n'
|
||||||
|
' │ │ parentData: index=0; layoutOffset=0.0\n'
|
||||||
|
' │ │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
||||||
|
' │ │ size: Size(800.0, 400.0)\n'
|
||||||
|
' │ │ maxWidth: 400.0\n'
|
||||||
|
' │ │ maxHeight: 400.0\n'
|
||||||
|
' │ │\n'
|
||||||
|
' │ └─child: RenderCustomPaint#00000\n'
|
||||||
|
' │ parentData: <none> (can use size)\n'
|
||||||
|
' │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
||||||
|
' │ size: Size(800.0, 400.0)\n'
|
||||||
|
' │\n'
|
||||||
|
' └─child with index 1: RenderLimitedBox#00000\n' // <----- no dashed line starts here
|
||||||
|
' │ parentData: index=1; layoutOffset=400.0\n'
|
||||||
|
' │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
||||||
|
' │ size: Size(800.0, 400.0)\n'
|
||||||
|
' │ maxWidth: 400.0\n'
|
||||||
|
' │ maxHeight: 400.0\n'
|
||||||
|
' │\n'
|
||||||
|
' └─child: RenderCustomPaint#00000\n'
|
||||||
|
' parentData: <none> (can use size)\n'
|
||||||
|
' constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
||||||
|
' size: Size(800.0, 400.0)\n'
|
||||||
));
|
));
|
||||||
const GlobalObjectKey<_LeafState>(0).currentState.setKeepAlive(true);
|
const GlobalObjectKey<_LeafState>(0).currentState.setKeepAlive(true);
|
||||||
await tester.drag(find.byType(ListView), const Offset(0.0, -1000.0));
|
await tester.drag(find.byType(ListView), const Offset(0.0, -1000.0));
|
||||||
@ -324,97 +335,108 @@ void main() {
|
|||||||
' │ diagnosis: insufficient data to draw conclusion (less than five\n'
|
' │ diagnosis: insufficient data to draw conclusion (less than five\n'
|
||||||
' │ repaints)\n'
|
' │ repaints)\n'
|
||||||
' │\n'
|
' │\n'
|
||||||
' └─child: RenderSemanticsGestureHandler#00000\n'
|
' └─child: _RenderExcludableScrollSemantics#00000\n'
|
||||||
' │ parentData: <none> (can use size)\n'
|
' │ parentData: <none> (can use size)\n'
|
||||||
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
||||||
|
' │ semantic boundary\n'
|
||||||
' │ size: Size(800.0, 600.0)\n'
|
' │ size: Size(800.0, 600.0)\n'
|
||||||
' │ gestures: vertical scroll\n'
|
|
||||||
' │\n'
|
' │\n'
|
||||||
' └─child: RenderPointerListener#00000\n'
|
' └─child: RenderSemanticsGestureHandler#00000\n'
|
||||||
' │ parentData: <none> (can use size)\n'
|
' │ parentData: <none> (can use size)\n'
|
||||||
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
||||||
' │ size: Size(800.0, 600.0)\n'
|
' │ size: Size(800.0, 600.0)\n'
|
||||||
' │ behavior: opaque\n'
|
' │ gestures: vertical scroll\n'
|
||||||
' │ listeners: down\n'
|
|
||||||
' │\n'
|
' │\n'
|
||||||
' └─child: RenderIgnorePointer#00000\n'
|
' └─child: RenderPointerListener#00000\n'
|
||||||
' │ parentData: <none> (can use size)\n'
|
' │ parentData: <none> (can use size)\n'
|
||||||
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
||||||
' │ size: Size(800.0, 600.0)\n'
|
' │ size: Size(800.0, 600.0)\n'
|
||||||
' │ ignoring: false\n'
|
' │ behavior: opaque\n'
|
||||||
' │ ignoringSemantics: false\n'
|
' │ listeners: down\n'
|
||||||
' │\n'
|
' │\n'
|
||||||
' └─child: RenderViewport#00000\n'
|
' └─child: RenderSemanticsAnnotations#00000\n'
|
||||||
' │ parentData: <none> (can use size)\n'
|
' │ parentData: <none> (can use size)\n'
|
||||||
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
||||||
' │ layer: OffsetLayer#00000\n'
|
|
||||||
' │ size: Size(800.0, 600.0)\n'
|
' │ size: Size(800.0, 600.0)\n'
|
||||||
' │ axisDirection: down\n'
|
|
||||||
' │ crossAxisDirection: right\n'
|
|
||||||
' │ offset: ScrollPositionWithSingleContext#00000(offset: 2000.0,\n'
|
|
||||||
' │ range: 0.0..39400.0, viewport: 600.0, ScrollableState,\n'
|
|
||||||
' │ AlwaysScrollableScrollPhysics -> ClampingScrollPhysics,\n'
|
|
||||||
' │ IdleScrollActivity#00000, ScrollDirection.idle)\n'
|
|
||||||
' │ anchor: 0.0\n'
|
|
||||||
' │\n'
|
' │\n'
|
||||||
' └─center child: RenderSliverFixedExtentList#00000 relayoutBoundary=up1\n'
|
' └─child: RenderIgnorePointer#00000\n'
|
||||||
' │ parentData: paintOffset=Offset(0.0, 0.0) (can use size)\n'
|
' │ parentData: <none> (can use size)\n'
|
||||||
' │ constraints: SliverConstraints(AxisDirection.down,\n'
|
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
||||||
' │ GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n'
|
' │ size: Size(800.0, 600.0)\n'
|
||||||
' │ 2000.0, remainingPaintExtent: 600.0, crossAxisExtent: 800.0,\n'
|
' │ ignoring: false\n'
|
||||||
' │ crossAxisDirection: AxisDirection.right,\n'
|
' │ ignoringSemantics: false\n'
|
||||||
' │ viewportMainAxisExtent: 600.0)\n'
|
|
||||||
' │ geometry: SliverGeometry(scrollExtent: 40000.0, paintExtent:\n'
|
|
||||||
' │ 600.0, maxPaintExtent: 40000.0, hasVisualOverflow: true)\n'
|
|
||||||
' │ currently live children: 5 to 6\n'
|
|
||||||
' │\n'
|
' │\n'
|
||||||
' ├─child with index 5: RenderLimitedBox#00000\n' // <----- this is index 5, not 0
|
' └─child: RenderViewport#00000\n'
|
||||||
' │ │ parentData: index=5; layoutOffset=2000.0\n'
|
' │ parentData: <none> (can use size)\n'
|
||||||
' │ │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
||||||
' │ │ size: Size(800.0, 400.0)\n'
|
' │ layer: OffsetLayer#00000\n'
|
||||||
' │ │ maxWidth: 400.0\n'
|
' │ size: Size(800.0, 600.0)\n'
|
||||||
' │ │ maxHeight: 400.0\n'
|
' │ axisDirection: down\n'
|
||||||
' │ │\n'
|
' │ crossAxisDirection: right\n'
|
||||||
' │ └─child: RenderCustomPaint#00000\n'
|
' │ offset: ScrollPositionWithSingleContext#00000(offset: 2000.0,\n'
|
||||||
' │ parentData: <none> (can use size)\n'
|
' │ range: 0.0..39400.0, viewport: 600.0, ScrollableState,\n'
|
||||||
' │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
' │ AlwaysScrollableScrollPhysics -> ClampingScrollPhysics,\n'
|
||||||
' │ size: Size(800.0, 400.0)\n'
|
' │ IdleScrollActivity#00000, ScrollDirection.idle)\n'
|
||||||
' │\n'
|
' │ anchor: 0.0\n'
|
||||||
' ├─child with index 6: RenderLimitedBox#00000\n'
|
|
||||||
' ╎ │ parentData: index=6; layoutOffset=2400.0\n'
|
|
||||||
' ╎ │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
|
||||||
' ╎ │ size: Size(800.0, 400.0)\n'
|
|
||||||
' ╎ │ maxWidth: 400.0\n'
|
|
||||||
' ╎ │ maxHeight: 400.0\n'
|
|
||||||
' ╎ │\n'
|
|
||||||
' ╎ └─child: RenderCustomPaint#00000\n'
|
|
||||||
' ╎ parentData: <none> (can use size)\n'
|
|
||||||
' ╎ constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
|
||||||
' ╎ size: Size(800.0, 400.0)\n'
|
|
||||||
' ╎\n'
|
|
||||||
' ╎╌child with index 0 (kept alive offstage): RenderLimitedBox#00000\n' // <----- this one is index 0 and is marked as being offstage
|
|
||||||
' ╎ │ parentData: index=0; keepAlive; layoutOffset=0.0\n'
|
|
||||||
' ╎ │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
|
||||||
' ╎ │ size: Size(800.0, 400.0)\n'
|
|
||||||
' ╎ │ maxWidth: 400.0\n'
|
|
||||||
' ╎ │ maxHeight: 400.0\n'
|
|
||||||
' ╎ │\n'
|
|
||||||
' ╎ └─child: RenderCustomPaint#00000\n'
|
|
||||||
' ╎ parentData: <none> (can use size)\n'
|
|
||||||
' ╎ constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
|
||||||
' ╎ size: Size(800.0, 400.0)\n'
|
|
||||||
' ╎\n' // <----- dashed line ends here
|
|
||||||
' └╌child with index 3 (kept alive offstage): RenderLimitedBox#00000\n'
|
|
||||||
' │ parentData: index=3; keepAlive; layoutOffset=1200.0\n'
|
|
||||||
' │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
|
||||||
' │ size: Size(800.0, 400.0)\n'
|
|
||||||
' │ maxWidth: 400.0\n'
|
|
||||||
' │ maxHeight: 400.0\n'
|
|
||||||
' │\n'
|
' │\n'
|
||||||
' └─child: RenderCustomPaint#00000\n'
|
' └─center child: RenderSliverFixedExtentList#00000 relayoutBoundary=up1\n'
|
||||||
' parentData: <none> (can use size)\n'
|
' │ parentData: paintOffset=Offset(0.0, 0.0) (can use size)\n'
|
||||||
' constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
' │ constraints: SliverConstraints(AxisDirection.down,\n'
|
||||||
' size: Size(800.0, 400.0)\n'
|
' │ GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n'
|
||||||
|
' │ 2000.0, remainingPaintExtent: 600.0, crossAxisExtent: 800.0,\n'
|
||||||
|
' │ crossAxisDirection: AxisDirection.right,\n'
|
||||||
|
' │ viewportMainAxisExtent: 600.0)\n'
|
||||||
|
' │ geometry: SliverGeometry(scrollExtent: 40000.0, paintExtent:\n'
|
||||||
|
' │ 600.0, maxPaintExtent: 40000.0, hasVisualOverflow: true)\n'
|
||||||
|
' │ currently live children: 5 to 6\n'
|
||||||
|
' │\n'
|
||||||
|
' ├─child with index 5: RenderLimitedBox#00000\n' // <----- this is index 5, not 0
|
||||||
|
' │ │ parentData: index=5; layoutOffset=2000.0\n'
|
||||||
|
' │ │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
||||||
|
' │ │ size: Size(800.0, 400.0)\n'
|
||||||
|
' │ │ maxWidth: 400.0\n'
|
||||||
|
' │ │ maxHeight: 400.0\n'
|
||||||
|
' │ │\n'
|
||||||
|
' │ └─child: RenderCustomPaint#00000\n'
|
||||||
|
' │ parentData: <none> (can use size)\n'
|
||||||
|
' │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
||||||
|
' │ size: Size(800.0, 400.0)\n'
|
||||||
|
' │\n'
|
||||||
|
' ├─child with index 6: RenderLimitedBox#00000\n'
|
||||||
|
' ╎ │ parentData: index=6; layoutOffset=2400.0\n'
|
||||||
|
' ╎ │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
||||||
|
' ╎ │ size: Size(800.0, 400.0)\n'
|
||||||
|
' ╎ │ maxWidth: 400.0\n'
|
||||||
|
' ╎ │ maxHeight: 400.0\n'
|
||||||
|
' ╎ │\n'
|
||||||
|
' ╎ └─child: RenderCustomPaint#00000\n'
|
||||||
|
' ╎ parentData: <none> (can use size)\n'
|
||||||
|
' ╎ constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
||||||
|
' ╎ size: Size(800.0, 400.0)\n'
|
||||||
|
' ╎\n'
|
||||||
|
' ╎╌child with index 0 (kept alive offstage): RenderLimitedBox#00000\n' // <----- this one is index 0 and is marked as being offstage
|
||||||
|
' ╎ │ parentData: index=0; keepAlive; layoutOffset=0.0\n'
|
||||||
|
' ╎ │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
||||||
|
' ╎ │ size: Size(800.0, 400.0)\n'
|
||||||
|
' ╎ │ maxWidth: 400.0\n'
|
||||||
|
' ╎ │ maxHeight: 400.0\n'
|
||||||
|
' ╎ │\n'
|
||||||
|
' ╎ └─child: RenderCustomPaint#00000\n'
|
||||||
|
' ╎ parentData: <none> (can use size)\n'
|
||||||
|
' ╎ constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
||||||
|
' ╎ size: Size(800.0, 400.0)\n'
|
||||||
|
' ╎\n' // <----- dashed line ends here
|
||||||
|
' └╌child with index 3 (kept alive offstage): RenderLimitedBox#00000\n'
|
||||||
|
' │ parentData: index=3; keepAlive; layoutOffset=1200.0\n'
|
||||||
|
' │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
||||||
|
' │ size: Size(800.0, 400.0)\n'
|
||||||
|
' │ maxWidth: 400.0\n'
|
||||||
|
' │ maxHeight: 400.0\n'
|
||||||
|
' │\n'
|
||||||
|
' └─child: RenderCustomPaint#00000\n'
|
||||||
|
' parentData: <none> (can use size)\n'
|
||||||
|
' constraints: BoxConstraints(w=800.0, h=400.0)\n'
|
||||||
|
' size: Size(800.0, 400.0)\n'
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -110,7 +110,6 @@ void main() {
|
|||||||
final TestSemantics expectedSemantics = new TestSemantics.root(
|
final TestSemantics expectedSemantics = new TestSemantics.root(
|
||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics.rootChild(
|
new TestSemantics.rootChild(
|
||||||
id: 2,
|
|
||||||
rect: TestSemantics.fullScreen,
|
rect: TestSemantics.fullScreen,
|
||||||
actions: SemanticsAction.tap.index,
|
actions: SemanticsAction.tap.index,
|
||||||
label: 'Dismiss',
|
label: 'Dismiss',
|
||||||
@ -118,7 +117,7 @@ void main() {
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
expect(semantics, hasSemantics(expectedSemantics));
|
expect(semantics, hasSemantics(expectedSemantics, ignoreId: true));
|
||||||
|
|
||||||
semantics.dispose();
|
semantics.dispose();
|
||||||
debugDefaultTargetPlatformOverride = null;
|
debugDefaultTargetPlatformOverride = null;
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:ui' show SemanticsFlag;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
@ -10,6 +12,10 @@ import 'package:flutter_test/flutter_test.dart';
|
|||||||
import 'semantics_tester.dart';
|
import 'semantics_tester.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
setUp(() {
|
||||||
|
debugResetSemanticsIdCounter();
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('MergeSemantics', (WidgetTester tester) async {
|
testWidgets('MergeSemantics', (WidgetTester tester) async {
|
||||||
final SemanticsTester semantics = new SemanticsTester(tester);
|
final SemanticsTester semantics = new SemanticsTester(tester);
|
||||||
|
|
||||||
@ -19,8 +25,14 @@ void main() {
|
|||||||
textDirection: TextDirection.ltr,
|
textDirection: TextDirection.ltr,
|
||||||
child: new Row(
|
child: new Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
const Text('test1'),
|
new Semantics(
|
||||||
const Text('test2'),
|
container: true,
|
||||||
|
child: const Text('test1'),
|
||||||
|
),
|
||||||
|
new Semantics(
|
||||||
|
container: true,
|
||||||
|
child: const Text('test2'),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -44,8 +56,14 @@ void main() {
|
|||||||
child: new MergeSemantics(
|
child: new MergeSemantics(
|
||||||
child: new Row(
|
child: new Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
const Text('test1'),
|
new Semantics(
|
||||||
const Text('test2'),
|
container: true,
|
||||||
|
child: const Text('test1'),
|
||||||
|
),
|
||||||
|
new Semantics(
|
||||||
|
container: true,
|
||||||
|
child: const Text('test2'),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -71,8 +89,14 @@ void main() {
|
|||||||
textDirection: TextDirection.ltr,
|
textDirection: TextDirection.ltr,
|
||||||
child: new Row(
|
child: new Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
const Text('test1'),
|
new Semantics(
|
||||||
const Text('test2'),
|
container: true,
|
||||||
|
child: const Text('test1'),
|
||||||
|
),
|
||||||
|
new Semantics(
|
||||||
|
container: true,
|
||||||
|
child: const Text('test2'),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -81,8 +105,8 @@ void main() {
|
|||||||
expect(semantics, hasSemantics(
|
expect(semantics, hasSemantics(
|
||||||
new TestSemantics.root(
|
new TestSemantics.root(
|
||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics.rootChild(id: 4, label: 'test1'),
|
new TestSemantics.rootChild(id: 6, label: 'test1'),
|
||||||
new TestSemantics.rootChild(id: 5, label: 'test2'),
|
new TestSemantics.rootChild(id: 7, label: 'test2'),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
ignoreRect: true,
|
ignoreRect: true,
|
||||||
@ -91,4 +115,49 @@ void main() {
|
|||||||
|
|
||||||
semantics.dispose();
|
semantics.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('MergeSemantics works if other nodes are implicitly merged into its node', (WidgetTester tester) async {
|
||||||
|
final SemanticsTester semantics = new SemanticsTester(tester);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
new Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: new MergeSemantics(
|
||||||
|
child: new Semantics(
|
||||||
|
selected: true, // this is implicitly merged into the MergeSemantics node
|
||||||
|
child: new Row(
|
||||||
|
children: <Widget>[
|
||||||
|
new Semantics(
|
||||||
|
container: true,
|
||||||
|
child: const Text('test1'),
|
||||||
|
),
|
||||||
|
new Semantics(
|
||||||
|
container: true,
|
||||||
|
child: const Text('test2'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(semantics, hasSemantics(
|
||||||
|
new TestSemantics.root(
|
||||||
|
children: <TestSemantics>[
|
||||||
|
new TestSemantics.rootChild(
|
||||||
|
id: 1,
|
||||||
|
flags: <SemanticsFlag>[
|
||||||
|
SemanticsFlag.isSelected,
|
||||||
|
],
|
||||||
|
label: 'test1\ntest2',
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
ignoreRect: true,
|
||||||
|
ignoreTransform: true,
|
||||||
|
));
|
||||||
|
|
||||||
|
semantics.dispose();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ void main() {
|
|||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics.rootChild(
|
new TestSemantics.rootChild(
|
||||||
id: 1,
|
id: 1,
|
||||||
tags: <SemanticsTag>[RenderSemanticsGestureHandler.useTwoPaneSemantics],
|
tags: <SemanticsTag>[RenderViewport.useTwoPaneSemantics],
|
||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
id: 5,
|
id: 5,
|
||||||
@ -89,7 +89,7 @@ void main() {
|
|||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics.rootChild(
|
new TestSemantics.rootChild(
|
||||||
id: 1,
|
id: 1,
|
||||||
tags: <SemanticsTag>[RenderSemanticsGestureHandler.useTwoPaneSemantics],
|
tags: <SemanticsTag>[RenderViewport.useTwoPaneSemantics],
|
||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
id: 5,
|
id: 5,
|
||||||
@ -112,7 +112,7 @@ void main() {
|
|||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
id: 4,
|
id: 4,
|
||||||
label: 'Semantics Test with Slivers',
|
label: 'Semantics Test with Slivers',
|
||||||
tags: <SemanticsTag>[RenderSemanticsGestureHandler.excludeFromScrolling],
|
tags: <SemanticsTag>[RenderViewport.excludeFromScrolling],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@ -132,7 +132,7 @@ void main() {
|
|||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics.rootChild(
|
new TestSemantics.rootChild(
|
||||||
id: 1,
|
id: 1,
|
||||||
tags: <SemanticsTag>[RenderSemanticsGestureHandler.useTwoPaneSemantics],
|
tags: <SemanticsTag>[RenderViewport.useTwoPaneSemantics],
|
||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
id: 5,
|
id: 5,
|
||||||
@ -203,7 +203,7 @@ void main() {
|
|||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics.rootChild(
|
new TestSemantics.rootChild(
|
||||||
id: 7,
|
id: 7,
|
||||||
tags: <SemanticsTag>[RenderSemanticsGestureHandler.useTwoPaneSemantics],
|
tags: <SemanticsTag>[RenderViewport.useTwoPaneSemantics],
|
||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
id: 10,
|
id: 10,
|
||||||
@ -257,7 +257,7 @@ void main() {
|
|||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics.rootChild(
|
new TestSemantics.rootChild(
|
||||||
id: 11,
|
id: 11,
|
||||||
tags: <SemanticsTag>[RenderSemanticsGestureHandler.useTwoPaneSemantics],
|
tags: <SemanticsTag>[RenderViewport.useTwoPaneSemantics],
|
||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
id: 17,
|
id: 17,
|
||||||
@ -339,7 +339,7 @@ void main() {
|
|||||||
new TestSemantics.rootChild(
|
new TestSemantics.rootChild(
|
||||||
id: 18,
|
id: 18,
|
||||||
rect: TestSemantics.fullScreen,
|
rect: TestSemantics.fullScreen,
|
||||||
tags: <SemanticsTag>[RenderSemanticsGestureHandler.useTwoPaneSemantics],
|
tags: <SemanticsTag>[RenderViewport.useTwoPaneSemantics],
|
||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
id: 23,
|
id: 23,
|
||||||
@ -371,7 +371,7 @@ void main() {
|
|||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
id: 22,
|
id: 22,
|
||||||
rect: new Rect.fromLTRB(0.0, 0.0, 120.0, 20.0),
|
rect: new Rect.fromLTRB(0.0, 0.0, 120.0, 20.0),
|
||||||
tags: <SemanticsTag>[RenderSemanticsGestureHandler.excludeFromScrolling],
|
tags: <SemanticsTag>[RenderViewport.excludeFromScrolling],
|
||||||
label: 'AppBar',
|
label: 'AppBar',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -422,7 +422,7 @@ void main() {
|
|||||||
new TestSemantics.rootChild(
|
new TestSemantics.rootChild(
|
||||||
id: 24,
|
id: 24,
|
||||||
rect: TestSemantics.fullScreen,
|
rect: TestSemantics.fullScreen,
|
||||||
tags: <SemanticsTag>[RenderSemanticsGestureHandler.useTwoPaneSemantics],
|
tags: <SemanticsTag>[RenderViewport.useTwoPaneSemantics],
|
||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
id: 29,
|
id: 29,
|
||||||
@ -454,7 +454,7 @@ void main() {
|
|||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
id: 28,
|
id: 28,
|
||||||
rect: new Rect.fromLTRB(0.0, 0.0, 120.0, 20.0),
|
rect: new Rect.fromLTRB(0.0, 0.0, 120.0, 20.0),
|
||||||
tags: <SemanticsTag>[RenderSemanticsGestureHandler.excludeFromScrolling],
|
tags: <SemanticsTag>[RenderViewport.excludeFromScrolling],
|
||||||
label: 'AppBar'
|
label: 'AppBar'
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -507,7 +507,7 @@ void main() {
|
|||||||
new TestSemantics.rootChild(
|
new TestSemantics.rootChild(
|
||||||
id: 30,
|
id: 30,
|
||||||
rect: TestSemantics.fullScreen,
|
rect: TestSemantics.fullScreen,
|
||||||
tags: <SemanticsTag>[RenderSemanticsGestureHandler.useTwoPaneSemantics],
|
tags: <SemanticsTag>[RenderViewport.useTwoPaneSemantics],
|
||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
id: 35,
|
id: 35,
|
||||||
@ -540,7 +540,7 @@ void main() {
|
|||||||
id: 34,
|
id: 34,
|
||||||
rect: new Rect.fromLTRB(0.0, 0.0, 120.0, 20.0),
|
rect: new Rect.fromLTRB(0.0, 0.0, 120.0, 20.0),
|
||||||
transform: new Matrix4.translation(new Vector3(0.0, 544.0, 0.0)),
|
transform: new Matrix4.translation(new Vector3(0.0, 544.0, 0.0)),
|
||||||
tags: <SemanticsTag>[RenderSemanticsGestureHandler.excludeFromScrolling],
|
tags: <SemanticsTag>[RenderViewport.excludeFromScrolling],
|
||||||
label: 'AppBar'
|
label: 'AppBar'
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -592,7 +592,7 @@ void main() {
|
|||||||
new TestSemantics.rootChild(
|
new TestSemantics.rootChild(
|
||||||
id: 36,
|
id: 36,
|
||||||
rect: TestSemantics.fullScreen,
|
rect: TestSemantics.fullScreen,
|
||||||
tags: <SemanticsTag>[RenderSemanticsGestureHandler.useTwoPaneSemantics],
|
tags: <SemanticsTag>[RenderViewport.useTwoPaneSemantics],
|
||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
id: 41,
|
id: 41,
|
||||||
@ -625,7 +625,7 @@ void main() {
|
|||||||
id: 40,
|
id: 40,
|
||||||
rect: new Rect.fromLTRB(0.0, 0.0, 120.0, 20.0),
|
rect: new Rect.fromLTRB(0.0, 0.0, 120.0, 20.0),
|
||||||
transform: new Matrix4.translation(new Vector3(0.0, 544.0, 0.0)),
|
transform: new Matrix4.translation(new Vector3(0.0, 544.0, 0.0)),
|
||||||
tags: <SemanticsTag>[RenderSemanticsGestureHandler.excludeFromScrolling],
|
tags: <SemanticsTag>[RenderViewport.excludeFromScrolling],
|
||||||
label: 'AppBar'
|
label: 'AppBar'
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user