Skip to content

Interactivité Flutter

L’interactivité est un aspect fondamental des applications Flutter. Elle permet aux utilisateurs d’interagir avec votre interface grâce aux gestes tactiles, aux boutons et autres éléments interactifs.

Flutter propose plusieurs types de boutons Material Design, chacun avec ses propres cas d’usage et styles visuels.

Le bouton élevé est le bouton principal recommandé pour les actions importantes. Il possède une ombre et se distingue clairement du fond.

ElevatedButton(
onPressed: () {
print('Bouton appuyé');
},
child: const Text('Action principale'),
)
ElevatedButton(
onPressed: () => context.push('/list'),
child: Text('Aller à la liste'),
)

Le bouton texte est utilisé pour les actions secondaires. Il n’a pas d’arrière-plan par défaut et convient parfaitement aux dialogues.

TextButton(
onPressed: () {
Navigator.of(context).pop(false);
},
child: const Text('Annuler'),
)

Le bouton avec contour offre un compromis visuel entre ElevatedButton et TextButton.

OutlinedButton(
onPressed: () {
print('Action secondaire');
},
child: const Text('Action secondaire'),
)

L’IconButton permet de créer des boutons avec des icônes, parfaits pour les barres d’outils et les actions compactes.

AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.of(context).pop(),
),
title: const Text('Mon écran'),
actions: [
IconButton(
icon: Icon(Icons.info),
onPressed: () => print('Infos'),
),
IconButton(
icon: Icon(Icons.settings),
onPressed: () => print('Paramètres'),
),
],
)
IconButton(
icon: const Icon(Icons.favorite),
iconSize: 32,
onPressed: () {
print('Ajouté aux favoris');
},
)

Le FAB est un bouton d’action flottant positionné au-dessus du contenu principal.

Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () => print('Action rapide'),
child: const Icon(Icons.add),
),
body: // votre contenu
)
FloatingActionButton.extended(
onPressed: () => print('Nouvelle action'),
label: const Text('Ajouter'),
icon: const Icon(Icons.add),
)

InkWell ajoute un effet de ripple Material Design à n’importe quel widget, le rendant interactif.

InkWell(
onTap: () {
print('Zone tapée');
},
child: Container(
padding: const EdgeInsets.all(16),
child: const Text('Tapez ici'),
),
)
Card(
child: InkWell(
onTap: () {
print('Carte sélectionnée');
},
borderRadius: BorderRadius.circular(8),
child: const Padding(
padding: EdgeInsets.all(16),
child: Text('Carte interactive'),
),
),
)

GestureDetector offre un contrôle granulaire sur la détection des gestes sans les effets visuels Material.

GestureDetector(
onTap: () => print('Simple tap'),
onDoubleTap: () => print('Double tap'),
onLongPress: () => print('Long press'),
child: Container(
width: 200,
height: 100,
color: Colors.blue,
child: const Center(
child: Text('Zone de gestes'),
),
),
)
GestureDetector(
onPanUpdate: (details) {
print('Glissement: ${details.delta}');
},
onPanEnd: (details) {
print('Fin du glissement');
},
child: Container(
width: double.infinity,
height: 200,
color: Colors.grey[300],
child: const Center(
child: Text('Glissez dans cette zone'),
),
),
)
Future<bool?> showConfirmDialog(BuildContext context) {
return showDialog<bool>(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('Confirmation'),
content: const Text('Êtes-vous sûr de vouloir continuer ?'),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: const Text('Annuler'),
),
ElevatedButton(
onPressed: () => Navigator.of(context).pop(true),
child: const Text('Confirmer'),
),
],
);
},
);
}
ElevatedButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DetailScreen(item: selectedItem),
),
);
},
child: const Text('Voir les détails'),
)
class CounterWidget extends StatefulWidget {
@override
_CounterWidgetState createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int counter = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(
'$counter',
style: Theme.of(context).textTheme.headlineMedium,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () {
setState(() {
counter--;
});
},
child: const Icon(Icons.remove),
),
ElevatedButton(
onPressed: () {
setState(() {
counter++;
});
},
child: const Icon(Icons.add),
),
],
),
],
);
}
}
class MainScreen extends StatefulWidget {
@override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
int currentIndex = 0;
final List<Widget> screens = [
HomeScreen(),
SearchScreen(),
ProfileScreen(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: screens[currentIndex],
bottomNavigationBar: BottomNavigationBar(
currentIndex: currentIndex,
onTap: (index) {
setState(() {
currentIndex = index;
});
},
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Accueil',
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'Recherche',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profil',
),
],
),
);
}
}
class CustomButton extends StatelessWidget {
final String text;
final VoidCallback? onPressed;
const CustomButton({
Key? key,
required this.text,
this.onPressed,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onPressed,
child: Text(text),
);
}
}
// Usage
CustomButton(
text: 'Mon bouton',
onPressed: () {
print('Bouton personnalisé pressé');
},
)
class ItemCard extends StatelessWidget {
final String item;
final Function(String) onItemSelected;
const ItemCard({
Key? key,
required this.item,
required this.onItemSelected,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Card(
child: InkWell(
onTap: () => onItemSelected(item),
child: Padding(
padding: const EdgeInsets.all(16),
child: Text(item),
),
),
);
}
}
ElevatedButton(
onPressed: isLoading ? null : () {
// Action du bouton
},
child: isLoading
? const CircularProgressIndicator()
: const Text('Valider'),
)
InkWell(
onTap: () {
// Vibration tactile
HapticFeedback.lightImpact();
// Action du bouton
performAction();
},
splashColor: Colors.blue.withOpacity(0.3),
highlightColor: Colors.blue.withOpacity(0.1),
child: Container(
padding: const EdgeInsets.all(16),
child: const Text('Bouton avec feedback'),
),
)
IconButton(
icon: const Icon(Icons.favorite),
onPressed: () {
// Action
},
tooltip: 'Ajouter aux favoris',
// Pour l'accessibilité
semanticLabel: 'Ajouter cet élément aux favoris',
)

L’interactivité est essentielle pour créer des applications Flutter engageantes. En combinant ces différents éléments - boutons, gestes et patterns d’interaction - vous pouvez créer des interfaces utilisateur intuitives et réactives.