Add option for custom actions to Semantics widget (#12695)
* Add option for custom actions to Semantics widget * review comments * review comment
This commit is contained in:
parent
311b57be42
commit
e3327af22a
@ -3179,6 +3179,14 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
|
||||
String value,
|
||||
String hint,
|
||||
TextDirection textDirection,
|
||||
VoidCallback onTap,
|
||||
VoidCallback onLongPress,
|
||||
VoidCallback onScrollLeft,
|
||||
VoidCallback onScrollRight,
|
||||
VoidCallback onScrollUp,
|
||||
VoidCallback onScrollDown,
|
||||
VoidCallback onIncrease,
|
||||
VoidCallback onDecrease,
|
||||
}) : assert(container != null),
|
||||
_container = container,
|
||||
_explicitChildNodes = explicitChildNodes,
|
||||
@ -3189,6 +3197,14 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
|
||||
_value = value,
|
||||
_hint = hint,
|
||||
_textDirection = textDirection,
|
||||
_onTap = onTap,
|
||||
_onLongPress = onLongPress,
|
||||
_onScrollLeft = onScrollLeft,
|
||||
_onScrollRight = onScrollRight,
|
||||
_onScrollUp = onScrollUp,
|
||||
_onScrollDown = onScrollDown,
|
||||
_onIncrease = onIncrease,
|
||||
_onDecrease = onDecrease,
|
||||
super(child);
|
||||
|
||||
/// If 'container' is true, this [RenderObject] will introduce a new
|
||||
@ -3317,6 +3333,170 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
|
||||
markNeedsSemanticsUpdate(onlyLocalUpdates: (value != null) == hadValue);
|
||||
}
|
||||
|
||||
/// The handler for [SemanticsAction.tap].
|
||||
///
|
||||
/// This is the semantic equivalent of a user briefly tapping the screen with
|
||||
/// the finger without moving it. For example, a button should implement this
|
||||
/// action.
|
||||
///
|
||||
/// VoiceOver users on iOS and TalkBack users on Android can trigger this
|
||||
/// action by double-tapping the screen while an element is focused.
|
||||
VoidCallback get onTap => _onTap;
|
||||
VoidCallback _onTap;
|
||||
set onTap(VoidCallback handler) {
|
||||
if (_onTap == handler)
|
||||
return;
|
||||
final bool hadValue = _onTap != null;
|
||||
_onTap = handler;
|
||||
if ((handler != null) == hadValue)
|
||||
markNeedsSemanticsUpdate(onlyLocalUpdates: true);
|
||||
}
|
||||
|
||||
/// The handler for [SemanticsAction.longPress].
|
||||
///
|
||||
/// This is the semantic equivalent of a user pressing and holding the screen
|
||||
/// with the finger for a few seconds without moving it.
|
||||
///
|
||||
/// VoiceOver users on iOS and TalkBack users on Android can trigger this
|
||||
/// action by double-tapping the screen without lifting the finger after the
|
||||
/// second tap.
|
||||
VoidCallback get onLongPress => _onLongPress;
|
||||
VoidCallback _onLongPress;
|
||||
set onLongPress(VoidCallback handler) {
|
||||
if (_onLongPress == handler)
|
||||
return;
|
||||
final bool hadValue = _onLongPress != null;
|
||||
_onLongPress = handler;
|
||||
if ((handler != null) != hadValue)
|
||||
markNeedsSemanticsUpdate(onlyLocalUpdates: true);
|
||||
}
|
||||
|
||||
/// The handler for [SemanticsAction.scrollLeft].
|
||||
///
|
||||
/// This is the semantic equivalent of a user moving their finger across the
|
||||
/// screen from right to left. It should be recognized by controls that are
|
||||
/// horizontally scrollable.
|
||||
///
|
||||
/// VoiceOver users on iOS can trigger this action by swiping left with three
|
||||
/// fingers. TalkBack users on Android can trigger this action by swiping
|
||||
/// right and then left in one motion path. On Android, [onScrollUp] and
|
||||
/// [onScrollLeft] share the same gesture. Therefore, only on of them should
|
||||
/// be provided.
|
||||
VoidCallback get onScrollLeft => _onScrollLeft;
|
||||
VoidCallback _onScrollLeft;
|
||||
set onScrollLeft(VoidCallback handler) {
|
||||
if (_onScrollLeft == handler)
|
||||
return;
|
||||
final bool hadValue = _onScrollLeft != null;
|
||||
_onScrollLeft = handler;
|
||||
if ((handler != null) != hadValue)
|
||||
markNeedsSemanticsUpdate(onlyLocalUpdates: true);
|
||||
}
|
||||
|
||||
/// The handler for [SemanticsAction.scrollRight].
|
||||
///
|
||||
/// This is the semantic equivalent of a user moving their finger across the
|
||||
/// screen from left to right. It should be recognized by controls that are
|
||||
/// horizontally scrollable.
|
||||
///
|
||||
/// VoiceOver users on iOS can trigger this action by swiping right with three
|
||||
/// fingers. TalkBack users on Android can trigger this action by swiping
|
||||
/// left and then right in one motion path. On Android, [onScrollDown] and
|
||||
/// [onScrollRight] share the same gesture. Therefore, only on of them should
|
||||
/// be provided.
|
||||
VoidCallback get onScrollRight => _onScrollRight;
|
||||
VoidCallback _onScrollRight;
|
||||
set onScrollRight(VoidCallback handler) {
|
||||
if (_onScrollRight == handler)
|
||||
return;
|
||||
final bool hadValue = _onScrollRight != null;
|
||||
_onScrollRight = handler;
|
||||
if ((handler != null) != hadValue)
|
||||
markNeedsSemanticsUpdate(onlyLocalUpdates: true);
|
||||
}
|
||||
|
||||
/// The handler for [SemanticsAction.scrollUp].
|
||||
///
|
||||
/// This is the semantic equivalent of a user moving their finger across the
|
||||
/// screen from bottom to top. It should be recognized by controls that are
|
||||
/// vertically scrollable.
|
||||
///
|
||||
/// VoiceOver users on iOS can trigger this action by swiping up with three
|
||||
/// fingers. TalkBack users on Android can trigger this action by swiping
|
||||
/// right and then left in one motion path. On Android, [onScrollUp] and
|
||||
/// [onScrollLeft] share the same gesture. Therefore, only on of them should
|
||||
/// be provided.
|
||||
VoidCallback get onScrollUp => _onScrollUp;
|
||||
VoidCallback _onScrollUp;
|
||||
set onScrollUp(VoidCallback handler) {
|
||||
if (_onScrollUp == handler)
|
||||
return;
|
||||
final bool hadValue = _onScrollUp != null;
|
||||
_onScrollUp = handler;
|
||||
if ((handler != null) != hadValue)
|
||||
markNeedsSemanticsUpdate(onlyLocalUpdates: true);
|
||||
}
|
||||
|
||||
/// The handler for [SemanticsAction.scrollDown].
|
||||
///
|
||||
/// This is the semantic equivalent of a user moving their finger across the
|
||||
/// screen from top to bottom. It should be recognized by controls that are
|
||||
/// vertically scrollable.
|
||||
///
|
||||
/// VoiceOver users on iOS can trigger this action by swiping down with three
|
||||
/// fingers. TalkBack users on Android can trigger this action by swiping
|
||||
/// left and then right in one motion path. On Android, [onScrollDown] and
|
||||
/// [onScrollRight] share the same gesture. Therefore, only on of them should
|
||||
/// be provided.
|
||||
VoidCallback get onScrollDown => _onScrollDown;
|
||||
VoidCallback _onScrollDown;
|
||||
set onScrollDown(VoidCallback handler) {
|
||||
if (_onScrollDown == handler)
|
||||
return;
|
||||
final bool hadValue = _onScrollDown != null;
|
||||
_onScrollDown = handler;
|
||||
if ((handler != null) != hadValue)
|
||||
markNeedsSemanticsUpdate(onlyLocalUpdates: true);
|
||||
}
|
||||
|
||||
/// The handler for [SemanticsAction.increase].
|
||||
///
|
||||
/// This is a request to increase the value represented by the widget. For
|
||||
/// example, this action might be recognized by a slider control.
|
||||
///
|
||||
/// VoiceOver users on iOS can trigger this action by swiping up with one
|
||||
/// finger. TalkBack users on Android can trigger this action by pressing the
|
||||
/// volume up button.
|
||||
VoidCallback get onIncrease => _onIncrease;
|
||||
VoidCallback _onIncrease;
|
||||
set onIncrease(VoidCallback handler) {
|
||||
if (_onIncrease == handler)
|
||||
return;
|
||||
final bool hadValue = _onIncrease != null;
|
||||
_onIncrease = handler;
|
||||
if ((handler != null) != hadValue)
|
||||
markNeedsSemanticsUpdate(onlyLocalUpdates: true);
|
||||
}
|
||||
|
||||
/// The handler for [SemanticsAction.decrease].
|
||||
///
|
||||
/// This is a request to decrease the value represented by the widget. For
|
||||
/// example, this action might be recognized by a slider control.
|
||||
///
|
||||
/// VoiceOver users on iOS can trigger this action by swiping down with one
|
||||
/// finger. TalkBack users on Android can trigger this action by pressing the
|
||||
/// volume down button.
|
||||
VoidCallback get onDecrease => _onDecrease;
|
||||
VoidCallback _onDecrease;
|
||||
set onDecrease(VoidCallback handler) {
|
||||
if (_onDecrease == handler)
|
||||
return;
|
||||
final bool hadValue = _onDecrease != null;
|
||||
_onDecrease = handler;
|
||||
if ((handler != null) != hadValue)
|
||||
markNeedsSemanticsUpdate(onlyLocalUpdates: true);
|
||||
}
|
||||
|
||||
@override
|
||||
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
||||
config.isSemanticBoundary = container;
|
||||
@ -3326,6 +3506,8 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
|
||||
config.isChecked = checked;
|
||||
if (selected != null)
|
||||
config.isSelected = selected;
|
||||
if (button != null)
|
||||
config.isButton = button;
|
||||
if (label != null)
|
||||
config.label = label;
|
||||
if (value != null)
|
||||
@ -3334,8 +3516,65 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
|
||||
config.hint = hint;
|
||||
if (textDirection != null)
|
||||
config.textDirection = textDirection;
|
||||
if (button != null)
|
||||
config.isButton = button;
|
||||
// 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 (onTap != null)
|
||||
config.addAction(SemanticsAction.tap, _performTap);
|
||||
if (onLongPress != null)
|
||||
config.addAction(SemanticsAction.longPress, _performLongPress);
|
||||
if (onScrollLeft != null)
|
||||
config.addAction(SemanticsAction.scrollLeft, _performScrollLeft);
|
||||
if (onScrollRight != null)
|
||||
config.addAction(SemanticsAction.scrollRight, _performScrollRight);
|
||||
if (onScrollUp != null)
|
||||
config.addAction(SemanticsAction.scrollUp, _performScrollUp);
|
||||
if (onScrollDown != null)
|
||||
config.addAction(SemanticsAction.scrollDown, _performScrollDown);
|
||||
if (onIncrease != null)
|
||||
config.addAction(SemanticsAction.increase, _performIncrease);
|
||||
if (onDecrease != null)
|
||||
config.addAction(SemanticsAction.decrease, _performDecrease);
|
||||
}
|
||||
|
||||
void _performTap() {
|
||||
if (onTap != null)
|
||||
onTap();
|
||||
}
|
||||
|
||||
void _performLongPress() {
|
||||
if (onLongPress != null)
|
||||
onLongPress();
|
||||
}
|
||||
|
||||
void _performScrollLeft() {
|
||||
if (onScrollLeft != null)
|
||||
onScrollLeft();
|
||||
}
|
||||
|
||||
void _performScrollRight() {
|
||||
if (onScrollRight != null)
|
||||
onScrollRight();
|
||||
}
|
||||
|
||||
void _performScrollUp() {
|
||||
if (onScrollUp != null)
|
||||
onScrollUp();
|
||||
}
|
||||
|
||||
void _performScrollDown() {
|
||||
if (onScrollDown != null)
|
||||
onScrollDown();
|
||||
}
|
||||
|
||||
void _performIncrease() {
|
||||
if (onIncrease != null)
|
||||
onIncrease();
|
||||
}
|
||||
|
||||
void _performDecrease() {
|
||||
if (onDecrease != null)
|
||||
onDecrease();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4456,6 +4456,14 @@ class Semantics extends SingleChildRenderObjectWidget {
|
||||
this.value,
|
||||
this.hint,
|
||||
this.textDirection,
|
||||
this.onTap,
|
||||
this.onLongPress,
|
||||
this.onScrollLeft,
|
||||
this.onScrollRight,
|
||||
this.onScrollUp,
|
||||
this.onScrollDown,
|
||||
this.onIncrease,
|
||||
this.onDecrease,
|
||||
}) : assert(container != null),
|
||||
super(key: key, child: child);
|
||||
|
||||
@ -4540,6 +4548,98 @@ class Semantics extends SingleChildRenderObjectWidget {
|
||||
return textDirection ?? (label != null || value != null || hint != null ? Directionality.of(context) : null);
|
||||
}
|
||||
|
||||
/// The handler for [SemanticsAction.tap].
|
||||
///
|
||||
/// This is the semantic equivalent of a user briefly tapping the screen with
|
||||
/// the finger without moving it. For example, a button should implement this
|
||||
/// action.
|
||||
///
|
||||
/// VoiceOver users on iOS and TalkBack users on Android can trigger this
|
||||
/// action by double-tapping the screen while an element is focused.
|
||||
final VoidCallback onTap;
|
||||
|
||||
/// The handler for [SemanticsAction.longPress].
|
||||
///
|
||||
/// This is the semantic equivalent of a user pressing and holding the screen
|
||||
/// with the finger for a few seconds without moving it.
|
||||
///
|
||||
/// VoiceOver users on iOS and TalkBack users on Android can trigger this
|
||||
/// action by double-tapping the screen without lifting the finger after the
|
||||
/// second tap.
|
||||
final VoidCallback onLongPress;
|
||||
|
||||
/// The handler for [SemanticsAction.scrollLeft].
|
||||
///
|
||||
/// This is the semantic equivalent of a user moving their finger across the
|
||||
/// screen from right to left. It should be recognized by controls that are
|
||||
/// horizontally scrollable.
|
||||
///
|
||||
/// VoiceOver users on iOS can trigger this action by swiping left with three
|
||||
/// fingers. TalkBack users on Android can trigger this action by swiping
|
||||
/// right and then left in one motion path. On Android, [onScrollUp] and
|
||||
/// [onScrollLeft] share the same gesture. Therefore, only on of them should
|
||||
/// be provided.
|
||||
final VoidCallback onScrollLeft;
|
||||
|
||||
/// The handler for [SemanticsAction.scrollRight].
|
||||
///
|
||||
/// This is the semantic equivalent of a user moving their finger across the
|
||||
/// screen from left to right. It should be recognized by controls that are
|
||||
/// horizontally scrollable.
|
||||
///
|
||||
/// VoiceOver users on iOS can trigger this action by swiping right with three
|
||||
/// fingers. TalkBack users on Android can trigger this action by swiping
|
||||
/// left and then right in one motion path. On Android, [onScrollDown] and
|
||||
/// [onScrollRight] share the same gesture. Therefore, only on of them should
|
||||
/// be provided.
|
||||
final VoidCallback onScrollRight;
|
||||
|
||||
/// The handler for [SemanticsAction.scrollUp].
|
||||
///
|
||||
/// This is the semantic equivalent of a user moving their finger across the
|
||||
/// screen from bottom to top. It should be recognized by controls that are
|
||||
/// vertically scrollable.
|
||||
///
|
||||
/// VoiceOver users on iOS can trigger this action by swiping up with three
|
||||
/// fingers. TalkBack users on Android can trigger this action by swiping
|
||||
/// right and then left in one motion path. On Android, [onScrollUp] and
|
||||
/// [onScrollLeft] share the same gesture. Therefore, only on of them should
|
||||
/// be provided.
|
||||
final VoidCallback onScrollUp;
|
||||
|
||||
/// The handler for [SemanticsAction.scrollDown].
|
||||
///
|
||||
/// This is the semantic equivalent of a user moving their finger across the
|
||||
/// screen from top to bottom. It should be recognized by controls that are
|
||||
/// vertically scrollable.
|
||||
///
|
||||
/// VoiceOver users on iOS can trigger this action by swiping down with three
|
||||
/// fingers. TalkBack users on Android can trigger this action by swiping
|
||||
/// left and then right in one motion path. On Android, [onScrollDown] and
|
||||
/// [onScrollRight] share the same gesture. Therefore, only on of them should
|
||||
/// be provided.
|
||||
final VoidCallback onScrollDown;
|
||||
|
||||
/// The handler for [SemanticsAction.increase].
|
||||
///
|
||||
/// This is a request to increase the value represented by the widget. For
|
||||
/// example, this action might be recognized by a slider control.
|
||||
///
|
||||
/// VoiceOver users on iOS can trigger this action by swiping up with one
|
||||
/// finger. TalkBack users on Android can trigger this action by pressing the
|
||||
/// volume up button.
|
||||
final VoidCallback onIncrease;
|
||||
|
||||
/// The handler for [SemanticsAction.decrease].
|
||||
///
|
||||
/// This is a request to decrease the value represented by the widget. For
|
||||
/// example, this action might be recognized by a slider control.
|
||||
///
|
||||
/// VoiceOver users on iOS can trigger this action by swiping down with one
|
||||
/// finger. TalkBack users on Android can trigger this action by pressing the
|
||||
/// volume down button.
|
||||
final VoidCallback onDecrease;
|
||||
|
||||
@override
|
||||
RenderSemanticsAnnotations createRenderObject(BuildContext context) {
|
||||
return new RenderSemanticsAnnotations(
|
||||
@ -4552,6 +4652,14 @@ class Semantics extends SingleChildRenderObjectWidget {
|
||||
value: value,
|
||||
hint: hint,
|
||||
textDirection: _getTextDirection(context),
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
onScrollLeft: onScrollLeft,
|
||||
onScrollRight: onScrollRight,
|
||||
onScrollUp: onScrollUp,
|
||||
onScrollDown: onScrollDown,
|
||||
onIncrease: onIncrease,
|
||||
onDecrease: onDecrease,
|
||||
);
|
||||
}
|
||||
|
||||
@ -4565,7 +4673,15 @@ class Semantics extends SingleChildRenderObjectWidget {
|
||||
..label = label
|
||||
..value = value
|
||||
..hint = hint
|
||||
..textDirection = _getTextDirection(context);
|
||||
..textDirection = _getTextDirection(context)
|
||||
..onTap = onTap
|
||||
..onLongPress = onLongPress
|
||||
..onScrollLeft = onScrollLeft
|
||||
..onScrollRight = onScrollRight
|
||||
..onScrollUp = onScrollUp
|
||||
..onScrollDown = onScrollDown
|
||||
..onIncrease = onIncrease
|
||||
..onDecrease = onDecrease;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -370,4 +370,147 @@ void main() {
|
||||
|
||||
expect(semantics, hasSemantics(expectedSemantics, ignoreTransform: true, ignoreRect: true, ignoreId: true));
|
||||
});
|
||||
|
||||
testWidgets('Semantics widget supports all actions', (WidgetTester tester) async {
|
||||
final SemanticsTester semantics = new SemanticsTester(tester);
|
||||
|
||||
final List<SemanticsAction> performedActions = <SemanticsAction>[];
|
||||
|
||||
await tester.pumpWidget(
|
||||
new Semantics(
|
||||
container: true,
|
||||
onTap: () => performedActions.add(SemanticsAction.tap),
|
||||
onLongPress: () => performedActions.add(SemanticsAction.longPress),
|
||||
onScrollLeft: () => performedActions.add(SemanticsAction.scrollLeft),
|
||||
onScrollRight: () => performedActions.add(SemanticsAction.scrollRight),
|
||||
onScrollUp: () => performedActions.add(SemanticsAction.scrollUp),
|
||||
onScrollDown: () => performedActions.add(SemanticsAction.scrollDown),
|
||||
onIncrease: () => performedActions.add(SemanticsAction.increase),
|
||||
onDecrease: () => performedActions.add(SemanticsAction.decrease),
|
||||
)
|
||||
);
|
||||
|
||||
final Set<SemanticsAction> allActions = SemanticsAction.values.values.toSet()
|
||||
..remove(SemanticsAction.showOnScreen); // showOnScreen is non user-exposed.
|
||||
|
||||
final int expectedId = 32;
|
||||
final TestSemantics expectedSemantics = new TestSemantics.root(
|
||||
children: <TestSemantics>[
|
||||
new TestSemantics.rootChild(
|
||||
id: expectedId,
|
||||
rect: TestSemantics.fullScreen,
|
||||
actions: allActions.fold(0, (int previous, SemanticsAction action) => previous | action.index)
|
||||
),
|
||||
],
|
||||
);
|
||||
expect(semantics, hasSemantics(expectedSemantics));
|
||||
|
||||
// Do the actions work?
|
||||
final SemanticsOwner semanticsOwner = tester.binding.pipelineOwner.semanticsOwner;
|
||||
int expectedLength = 1;
|
||||
for (SemanticsAction action in allActions) {
|
||||
semanticsOwner.performAction(expectedId, action);
|
||||
expect(performedActions.length, expectedLength);
|
||||
expect(performedActions.last, action);
|
||||
expectedLength += 1;
|
||||
}
|
||||
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('Actions can be replaced without triggering semantics update', (WidgetTester tester) async {
|
||||
final SemanticsTester semantics = new SemanticsTester(tester);
|
||||
int semanticsUpdateCount = 0;
|
||||
tester.binding.pipelineOwner.ensureSemantics(
|
||||
listener: () {
|
||||
semanticsUpdateCount += 1;
|
||||
}
|
||||
);
|
||||
|
||||
final List<String> performedActions = <String>[];
|
||||
|
||||
await tester.pumpWidget(
|
||||
new Semantics(
|
||||
container: true,
|
||||
onTap: () => performedActions.add('first'),
|
||||
),
|
||||
);
|
||||
|
||||
final int expectedId = 35;
|
||||
final TestSemantics expectedSemantics = new TestSemantics.root(
|
||||
children: <TestSemantics>[
|
||||
new TestSemantics.rootChild(
|
||||
id: expectedId,
|
||||
rect: TestSemantics.fullScreen,
|
||||
actions: SemanticsAction.tap.index,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
final SemanticsOwner semanticsOwner = tester.binding.pipelineOwner.semanticsOwner;
|
||||
|
||||
expect(semantics, hasSemantics(expectedSemantics));
|
||||
semanticsOwner.performAction(expectedId, SemanticsAction.tap);
|
||||
expect(semanticsUpdateCount, 1);
|
||||
expect(performedActions, <String>['first']);
|
||||
|
||||
semanticsUpdateCount = 0;
|
||||
performedActions.clear();
|
||||
|
||||
// Updating existing handler should not trigger semantics update
|
||||
await tester.pumpWidget(
|
||||
new Semantics(
|
||||
container: true,
|
||||
onTap: () => performedActions.add('second'),
|
||||
),
|
||||
);
|
||||
|
||||
expect(semantics, hasSemantics(expectedSemantics));
|
||||
semanticsOwner.performAction(expectedId, SemanticsAction.tap);
|
||||
expect(semanticsUpdateCount, 0);
|
||||
expect(performedActions, <String>['second']);
|
||||
|
||||
semanticsUpdateCount = 0;
|
||||
performedActions.clear();
|
||||
|
||||
// Adding a handler works
|
||||
await tester.pumpWidget(
|
||||
new Semantics(
|
||||
container: true,
|
||||
onTap: () => performedActions.add('second'),
|
||||
onLongPress: () => performedActions.add('longPress'),
|
||||
),
|
||||
);
|
||||
|
||||
final TestSemantics expectedSemanticsWithLongPress = new TestSemantics.root(
|
||||
children: <TestSemantics>[
|
||||
new TestSemantics.rootChild(
|
||||
id: expectedId,
|
||||
rect: TestSemantics.fullScreen,
|
||||
actions: SemanticsAction.tap.index | SemanticsAction.longPress.index,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
expect(semantics, hasSemantics(expectedSemanticsWithLongPress));
|
||||
semanticsOwner.performAction(expectedId, SemanticsAction.longPress);
|
||||
expect(semanticsUpdateCount, 1);
|
||||
expect(performedActions, <String>['longPress']);
|
||||
|
||||
semanticsUpdateCount = 0;
|
||||
performedActions.clear();
|
||||
|
||||
// Removing a handler works
|
||||
await tester.pumpWidget(
|
||||
new Semantics(
|
||||
container: true,
|
||||
onTap: () => performedActions.add('second'),
|
||||
),
|
||||
);
|
||||
|
||||
expect(semantics, hasSemantics(expectedSemantics));
|
||||
expect(semanticsUpdateCount, 1);
|
||||
|
||||
semantics.dispose();
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user