SelectionArea on iOS should toggle the context menu when tapping on the previous selection (#132851)
https://github.com/flutter/flutter/assets/948037/210fdee4-d922-422b-a257-4ee586a3814f Related: https://github.com/flutter/flutter/issues/129583
This commit is contained in:
parent
d5a162b788
commit
2ecb8866a2
@ -341,7 +341,20 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe
|
|||||||
_gestureRecognizers[TapGestureRecognizer] = GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>(
|
_gestureRecognizers[TapGestureRecognizer] = GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>(
|
||||||
() => TapGestureRecognizer(debugOwner: this),
|
() => TapGestureRecognizer(debugOwner: this),
|
||||||
(TapGestureRecognizer instance) {
|
(TapGestureRecognizer instance) {
|
||||||
instance.onTap = _clearSelection;
|
instance.onTapUp = (TapUpDetails details) {
|
||||||
|
if (defaultTargetPlatform == TargetPlatform.iOS && _positionIsOnActiveSelection(globalPosition: details.globalPosition)) {
|
||||||
|
// On iOS when the tap occurs on the previous selection, instead of
|
||||||
|
// moving the selection, the context menu will be toggled.
|
||||||
|
final bool toolbarIsVisible = _selectionOverlay?.toolbarIsVisible ?? false;
|
||||||
|
if (toolbarIsVisible) {
|
||||||
|
hideToolbar(false);
|
||||||
|
} else {
|
||||||
|
_showToolbar(location: details.globalPosition);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_clearSelection();
|
||||||
|
}
|
||||||
|
};
|
||||||
instance.onSecondaryTapDown = _handleRightClickDown;
|
instance.onSecondaryTapDown = _handleRightClickDown;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -886,6 +886,78 @@ void main() {
|
|||||||
await gesture.up();
|
await gesture.up();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'single tap on the previous selection toggles the toolbar on iOS',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
Set<ContextMenuButtonType> buttonTypes = <ContextMenuButtonType>{};
|
||||||
|
final UniqueKey toolbarKey = UniqueKey();
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: SelectableRegion(
|
||||||
|
focusNode: FocusNode(),
|
||||||
|
selectionControls: materialTextSelectionHandleControls,
|
||||||
|
contextMenuBuilder: (
|
||||||
|
BuildContext context,
|
||||||
|
SelectableRegionState selectableRegionState,
|
||||||
|
) {
|
||||||
|
buttonTypes = selectableRegionState.contextMenuButtonItems
|
||||||
|
.map((ContextMenuButtonItem buttonItem) => buttonItem.type)
|
||||||
|
.toSet();
|
||||||
|
return SizedBox.shrink(key: toolbarKey);
|
||||||
|
},
|
||||||
|
child: const Column(
|
||||||
|
children: <Widget>[
|
||||||
|
Text('How are you?'),
|
||||||
|
Text('Good, and you?'),
|
||||||
|
Text('Fine, thank you.'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(buttonTypes.isEmpty, true);
|
||||||
|
expect(find.byKey(toolbarKey), findsNothing);
|
||||||
|
|
||||||
|
final RenderParagraph paragraph = tester.renderObject<RenderParagraph>(find.descendant(of: find.text('How are you?'), matching: find.byType(RichText)));
|
||||||
|
final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph, 2));
|
||||||
|
addTearDown(gesture.removePointer);
|
||||||
|
await tester.pump(const Duration(milliseconds: 500));
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(paragraph.selections[0], const TextSelection(baseOffset: 0, extentOffset: 3));
|
||||||
|
expect(buttonTypes, contains(ContextMenuButtonType.copy));
|
||||||
|
expect(buttonTypes, contains(ContextMenuButtonType.selectAll));
|
||||||
|
expect(find.byKey(toolbarKey), findsOneWidget);
|
||||||
|
|
||||||
|
await gesture.down(textOffsetToPosition(paragraph, 2));
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(paragraph.selections[0], const TextSelection(baseOffset: 0, extentOffset: 3));
|
||||||
|
expect(buttonTypes, contains(ContextMenuButtonType.copy));
|
||||||
|
expect(buttonTypes, contains(ContextMenuButtonType.selectAll));
|
||||||
|
expect(find.byKey(toolbarKey), findsNothing);
|
||||||
|
|
||||||
|
await gesture.down(textOffsetToPosition(paragraph, 2));
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(paragraph.selections[0], const TextSelection(baseOffset: 0, extentOffset: 3));
|
||||||
|
expect(buttonTypes, contains(ContextMenuButtonType.copy));
|
||||||
|
expect(buttonTypes, contains(ContextMenuButtonType.selectAll));
|
||||||
|
expect(find.byKey(toolbarKey), findsOneWidget);
|
||||||
|
|
||||||
|
// Clear selection.
|
||||||
|
await tester.tapAt(textOffsetToPosition(paragraph, 9));
|
||||||
|
await tester.pump();
|
||||||
|
expect(paragraph.selections.isEmpty, true);
|
||||||
|
expect(find.byKey(toolbarKey), findsNothing);
|
||||||
|
},
|
||||||
|
variant: TargetPlatformVariant.only(TargetPlatform.iOS),
|
||||||
|
skip: kIsWeb, // [intended] Web uses its native context menu.
|
||||||
|
);
|
||||||
|
|
||||||
testWidgets(
|
testWidgets(
|
||||||
'right-click mouse can select word at position on Apple platforms',
|
'right-click mouse can select word at position on Apple platforms',
|
||||||
(WidgetTester tester) async {
|
(WidgetTester tester) async {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user