Présentation du package
Le package experimental/context_menus est un outil expérimental pour Flutter, conçu pour créer et personnaliser des menus contextuels multiplateformes. Il prend en charge des scénarios tels que la barre d'outils de sélection de texte sur mobile et le menu clic droit sur desktop. Ce package offre une flexibilité élevée avec des fonctionnalités telles que des sous-menus en cascade, la personnalisation des boutons, et une adaptation optimale pour HarmonyOS, garantissant une expérience utilisateur cohérente.
Fonctionnalités principales :
- Création de menus contextuels n'imoprte où dans l'application
- Support des sous-menus imbriqués
- Personnalisation complète des boutons et actions
- Modification de l'ordre et du comportmeent des boutons par défaut
- Compatibilité avec les sélections de texte et les scénarios non textuels
- Adaptation native pour HarmonyOS
Intégration dans un projet HarmonyOS
1. Ajout des dépendances
Étant donné la nature expérimentale du package, il doit être importé via Git. Modifiez le fichier pubspec.yaml de votre projet Flutter pour HarmonyOS comme suit :
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
url_launcher: ^6.1.6
context_menus:
git:
url: "https://github.com/flutter/samples.git"
path: "experimental/context_menus"
2. Composants et API essentiels
ContextMenuRegion
Un widget enveloppant qui détecte les gestes de clic droit ou d'appui long pour déclencher un menu contextuel :
ContextMenuRegion({
Key? key,
required Widget child,
required ContextMenuBuilder builder,
});
ContextMenuBuilder
Un calllback pour construire le contenu du menu :
typedef ContextMenuBuilder = Widget Function(BuildContext context, Offset position);
ContextMenuController
Un contrôleur pour gérer l'affichage et la fermeture du menu :
final controller = ContextMenuController();
// Afficher le menu
controller.show(
context: context,
contextMenuBuilder: (ctx) => /* Widget du menu */,
);
// Fermer le menu
controller.remove();
3. Exemples d'utilisation
Menu contextuel sur un élément quelconque
import 'package:flutter/material.dart';
import 'package:context_menus/context_menu_region.dart';
class GenericMenuDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ContextMenuRegion(
child: Container(
color: Colors.blueGrey[50],
padding: EdgeInsets.all(20),
child: Center(
child: Text('Effectuez un clic droit ou un appui long pour ouvrir le menu'),
),
),
builder: (context, position) {
return Card(
elevation: 8,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
leading: Icon(Icons.copy),
title: Text('Copier'),
onTap: () {
// Logique de copie
Navigator.pop(context);
},
),
ListTile(
leading: Icon(Icons.cut),
title: Text('Couper'),
onTap: () {
// Logique de coupe
Navigator.pop(context);
},
),
ListTile(
leading: Icon(Icons.paste),
title: Text('Coller'),
onTap: () {
// Logique de collage
Navigator.pop(context);
},
),
],
),
);
},
);
}
}
Menu avec sous-menus imbriqués
import 'package:flutter/material.dart';
import 'package:context_menus/context_menu_region.dart';
class NestedMenuDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ContextMenuRegion(
child: Container(
color: Colors.green[50],
padding: EdgeInsets.all(20),
child: Center(
child: Text('Clic droit pour un menu avec sous-menus'),
),
),
builder: (context, position) {
return MenuBar(children: [
SubmenuButton(
menuChildren: [
MenuItemButton(
child: Text('Choix A'),
onPressed: () {
// Action pour Choix A
Navigator.pop(context);
},
),
MenuItemButton(
child: Text('Choix B'),
onPressed: () {
// Action pour Choix B
Navigator.pop(context);
},
),
],
child: Text('Menu principal'),
),
]);
},
);
}
}
Personnalisation du menu de sélection de texte
import 'package:flutter/material.dart';
class TextSelectionMenuCustom extends StatelessWidget {
@override
Widget build(BuildContext context) {
return TextField(
maxLines: null,
decoration: InputDecoration(
hintText: 'Tapez du texte, puis sélectionnez-le pour voir le menu',
border: OutlineInputBorder(),
contentPadding: EdgeInsets.all(16),
),
contextMenuBuilder: (context, state) {
return AdaptiveTextSelectionToolbar.buttonItems(
anchors: state.contextMenuAnchors,
buttonItems: <contextmenubuttonitem>[],
);
},
);
}
}</contextmenubuttonitem>
Menu contextuel sur une image
import 'package:flutter/material.dart';
import 'package:context_menus/context_menu_region.dart';
import 'package:url_launcher/url_launcher.dart';
class ImageMenuDemo extends StatelessWidget {
final String imageSource = 'https://example.com/sample-image.jpg';
@override
Widget build(BuildContext context) {
return ContextMenuRegion(
child: Card(
elevation: 4,
child: Image.network(imageSource, width: 300, height: 200, fit: BoxFit.cover),
),
builder: (context, position) {
return Card(
elevation: 8,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
leading: Icon(Icons.open_in_new),
title: Text('Ouvrir dans le navigateur'),
onTap: () {
launchUrl(Uri.parse(imageSource));
Navigator.pop(context);
},
),
ListTile(
leading: Icon(Icons.copy),
title: Text('Copier le lien'),
onTap: () {
// Logique de copie de lien
Navigator.pop(context);
},
),
ListTile(
leading: Icon(Icons.download),
title: Text('Télécharger'),
onTap: () {
// Logique de téléchargement
Navigator.pop(context);
},
),
],
),
);
},
);
}
}