À quoi servent les FocusNodes dans Flutter ?
Les FocusNode sont des objets dans Flutter qui permettent de changer rapidement le focus, sur un widget. Ils peuvent être utilisés avec une grande variété de widgets, qu’il s’agisse de boutons, de champs de texte, ou même des widgets personnalisés. Voici leurs principales utilités :
- Gérer la navigation au clavier : Par exemple, vous pouvez utiliser les FocusNodes pour passer d’un champ de texte à un autre en appuyant sur la touche « Tab ».
- Contrôler dynamiquement le focus : Vous pouvez programmer des transitions de focus, par exemple pour déplacer le focus vers un widget spécifique après une action utilisateur.
- Optimiser l’expérience utilisateur : En gérant le focus, vous pouvez guider l’utilisateur à travers une interface complexe, comme un formulaire ou une liste interactive.
En résumé, les FocusNode permettent de rendre une application plus intuitive et accessible pour les utilisateurs.
Comment utiliser les FocusNodes ?
Pour illustrercomment vous pouvez mettre en place des FocusNode, voici une application Flutter simple avec un SingleChildScrollView contenant une liste de boutons. Chaque bouton, lorsqu’il est pressé, passe le focus au bouton suivant. Le dernier bouton ramène le focus au premier, créant ainsi une navigation circulaire.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: const FocusNodeExample(),
);
}
}
class FocusNodeExample extends StatefulWidget {
const FocusNodeExample({super.key});
@override
_FocusNodeExampleState createState() => _FocusNodeExampleState();
}
class _FocusNodeExampleState extends State<FocusNodeExample> {
// Liste des FocusNode pour chaque bouton
final List<FocusNode> _focusNodes = List.generate(5, (_) => FocusNode());
// ScrollController pour gérer le défilement
final ScrollController _scrollController = ScrollController();
// Clés globales pour chaque bouton afin de calculer leur position
final List<GlobalKey> _buttonKeys = List.generate(5, (_) => GlobalKey());
@override
void initState() {
super.initState();
// Donner le focus au premier bouton au démarrage
WidgetsBinding.instance.addPostFrameCallback((_) {
_focusNodes[0].requestFocus();
});
}
@override
void dispose() {
// Nettoyer les FocusNode et le ScrollController
for (var node in _focusNodes) {
node.dispose();
}
_scrollController.dispose();
super.dispose();
}
// Fonction pour passer au bouton suivant et défiler
void _moveFocus(int currentIndex) {
// Calculer l'index du bouton suivant (boucle au premier après le dernier)
final nextIndex = (currentIndex + 1) % _focusNodes.length;
// Donner le focus au bouton suivant
_focusNodes[nextIndex].requestFocus();
// Obtenir la position du bouton suivant pour le défilement
final RenderBox? renderBox =
_buttonKeys[nextIndex].currentContext?.findRenderObject() as RenderBox?;
if (renderBox != null) {
final position = renderBox.localToGlobal(Offset.zero).dy;
// Calculer la position de défilement pour centrer le bouton
final scrollOffset = position -
(MediaQuery.of(context).size.height / 2) +
(renderBox.size.height / 2);
// Animer le défilement vers le bouton focalisé
_scrollController.animateTo(
scrollOffset.clamp(0, _scrollController.position.maxScrollExtent),
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Exemple de FocusNode avec Scroll'),
),
body: SingleChildScrollView(
controller: _scrollController, // Associer le ScrollController
padding: const EdgeInsets.all(16.0),
child: Column(
children: List.generate(_focusNodes.length, (index) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 100.0),
child: ElevatedButton(
key: _buttonKeys[
index], // Clé pour repérer la position du bouton
focusNode: _focusNodes[index], // Associer le FocusNode
onPressed: () {
_moveFocus(index); // Déplacer le focus et défiler
},
child: Text('Bouton ${index + 1}'),
),
);
}),
),
),
);
}
}
