mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Disable context menu (#128365)
## Description Changes the context menu example for `MenuAnchor` so that it uses right-click, or (on macOS and iOS only) ctrl-left-click, for the context menu. Also disables the browser context menu on web platforms. ## Tests - Updated test to reflect new triggers.
This commit is contained in:
parent
5328bd9ae0
commit
36f73cf645
@ -2,6 +2,7 @@
|
|||||||
// 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 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
@ -41,6 +42,7 @@ class _MyContextMenuState extends State<MyContextMenu> {
|
|||||||
final FocusNode _buttonFocusNode = FocusNode(debugLabel: 'Menu Button');
|
final FocusNode _buttonFocusNode = FocusNode(debugLabel: 'Menu Button');
|
||||||
final MenuController _menuController = MenuController();
|
final MenuController _menuController = MenuController();
|
||||||
ShortcutRegistryEntry? _shortcutsEntry;
|
ShortcutRegistryEntry? _shortcutsEntry;
|
||||||
|
bool _menuWasEnabled = false;
|
||||||
|
|
||||||
Color get backgroundColor => _backgroundColor;
|
Color get backgroundColor => _backgroundColor;
|
||||||
Color _backgroundColor = Colors.red;
|
Color _backgroundColor = Colors.red;
|
||||||
@ -62,6 +64,12 @@ class _MyContextMenuState extends State<MyContextMenu> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_disableContextMenu();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didChangeDependencies() {
|
void didChangeDependencies() {
|
||||||
super.didChangeDependencies();
|
super.didChangeDependencies();
|
||||||
@ -84,15 +92,38 @@ class _MyContextMenuState extends State<MyContextMenu> {
|
|||||||
void dispose() {
|
void dispose() {
|
||||||
_shortcutsEntry?.dispose();
|
_shortcutsEntry?.dispose();
|
||||||
_buttonFocusNode.dispose();
|
_buttonFocusNode.dispose();
|
||||||
|
_reenableContextMenu();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _disableContextMenu() async {
|
||||||
|
if (!kIsWeb) {
|
||||||
|
// Does nothing on non-web platforms.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_menuWasEnabled = BrowserContextMenu.enabled;
|
||||||
|
if (_menuWasEnabled) {
|
||||||
|
await BrowserContextMenu.disableContextMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _reenableContextMenu() {
|
||||||
|
if (!kIsWeb) {
|
||||||
|
// Does nothing on non-web platforms.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_menuWasEnabled && !BrowserContextMenu.enabled) {
|
||||||
|
BrowserContextMenu.enableContextMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(50),
|
padding: const EdgeInsets.all(50),
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTapDown: _handleTapDown,
|
onTapDown: _handleTapDown,
|
||||||
|
onSecondaryTapDown: _handleSecondaryTapDown,
|
||||||
child: MenuAnchor(
|
child: MenuAnchor(
|
||||||
controller: _menuController,
|
controller: _menuController,
|
||||||
anchorTapClosesMenu: true,
|
anchorTapClosesMenu: true,
|
||||||
@ -142,7 +173,7 @@ class _MyContextMenuState extends State<MyContextMenu> {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
const Padding(
|
const Padding(
|
||||||
padding: EdgeInsets.all(8.0),
|
padding: EdgeInsets.all(8.0),
|
||||||
child: Text('Ctrl-click anywhere on the background to show the menu.'),
|
child: Text('Right-click anywhere on the background to show the menu.'),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(12.0),
|
padding: const EdgeInsets.all(12.0),
|
||||||
@ -185,13 +216,29 @@ class _MyContextMenuState extends State<MyContextMenu> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleTapDown(TapDownDetails details) {
|
void _handleSecondaryTapDown(TapDownDetails details) {
|
||||||
if (!HardwareKeyboard.instance.logicalKeysPressed.contains(LogicalKeyboardKey.controlLeft) &&
|
|
||||||
!HardwareKeyboard.instance.logicalKeysPressed.contains(LogicalKeyboardKey.controlRight)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_menuController.open(position: details.localPosition);
|
_menuController.open(position: details.localPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _handleTapDown(TapDownDetails details) {
|
||||||
|
switch (defaultTargetPlatform) {
|
||||||
|
case TargetPlatform.android:
|
||||||
|
case TargetPlatform.fuchsia:
|
||||||
|
case TargetPlatform.linux:
|
||||||
|
case TargetPlatform.windows:
|
||||||
|
// Don't open the menu on these platforms with a Ctrl-tap (or a
|
||||||
|
// tap).
|
||||||
|
break;
|
||||||
|
case TargetPlatform.iOS:
|
||||||
|
case TargetPlatform.macOS:
|
||||||
|
// Only open the menu on these platforms if the control button is down
|
||||||
|
// when the tap occurs.
|
||||||
|
if (HardwareKeyboard.instance.logicalKeysPressed.contains(LogicalKeyboardKey.controlLeft) ||
|
||||||
|
HardwareKeyboard.instance.logicalKeysPressed.contains(LogicalKeyboardKey.controlRight)) {
|
||||||
|
_menuController.open(position: details.localPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ContextMenuApp extends StatelessWidget {
|
class ContextMenuApp extends StatelessWidget {
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// 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 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_api_samples/material/menu_anchor/menu_anchor.1.dart' as example;
|
import 'package:flutter_api_samples/material/menu_anchor/menu_anchor.1.dart' as example;
|
||||||
@ -18,15 +19,13 @@ void main() {
|
|||||||
|
|
||||||
await tester.pumpWidget(const example.ContextMenuApp());
|
await tester.pumpWidget(const example.ContextMenuApp());
|
||||||
|
|
||||||
await tester.sendKeyDownEvent(LogicalKeyboardKey.controlRight);
|
await tester.tapAt(const Offset(100, 200), buttons: kSecondaryButton);
|
||||||
await tester.tapAt(const Offset(100, 200));
|
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
expect(tester.getRect(findMenu()), equals(const Rect.fromLTRB(100.0, 200.0, 433.0, 360.0)));
|
expect(tester.getRect(findMenu()), equals(const Rect.fromLTRB(100.0, 200.0, 433.0, 360.0)));
|
||||||
|
|
||||||
// Make sure tapping in a different place causes the menu to move.
|
// Make sure tapping in a different place causes the menu to move.
|
||||||
await tester.tapAt(const Offset(200, 100));
|
await tester.tapAt(const Offset(200, 100), buttons: kSecondaryButton);
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
await tester.sendKeyUpEvent(LogicalKeyboardKey.controlRight);
|
|
||||||
|
|
||||||
expect(tester.getRect(findMenu()), equals(const Rect.fromLTRB(200.0, 100.0, 533.0, 260.0)));
|
expect(tester.getRect(findMenu()), equals(const Rect.fromLTRB(200.0, 100.0, 533.0, 260.0)));
|
||||||
|
|
||||||
@ -67,8 +66,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Open the menu so we can look for state changes reflected in the menu.
|
// Open the menu so we can look for state changes reflected in the menu.
|
||||||
await tester.sendKeyDownEvent(LogicalKeyboardKey.controlRight);
|
await tester.tapAt(const Offset(100, 200), buttons: kSecondaryButton);
|
||||||
await tester.tapAt(const Offset(100, 200));
|
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
|
|
||||||
expect(find.text(example.MenuEntry.showMessage.label), findsOneWidget);
|
expect(find.text(example.MenuEntry.showMessage.label), findsOneWidget);
|
||||||
|
Loading…
Reference in New Issue
Block a user