Vous voulez créer votre première application mobile, mais ne savez pas par où commencer ? Dans ce tutoriel, nous construisons ensemble une vraie application Flutter : une liste de tâches où l'on peut ajouter une tâche, la cocher quand elle est faite et la supprimer d'un glissement du doigt. À la fin, vous saurez lancer l'application sur votre téléphone Android et produire le fichier à installer.

Niveau : débutant. Durée : environ une heure, installation comprise. Le code de ce tutoriel a été vérifié avec Flutter 3.38 : aucune erreur d'analyse, test automatique réussi.

Pourquoi Flutter ?

Flutter, créé par Google, permet d'écrire un seul code pour obtenir une application Android et une application iPhone. C'est la technologie que nous utilisons chez NEWTIV pour la plupart de nos applications. Pour comparer avec les autres approches, lisez notre article sur le choix entre application native, Flutter et PWA.

Étape 1 : installer Flutter

  1. Téléchargez Flutter depuis le site officiel flutter.dev (rubrique « Get started ») et suivez le guide d'installation de votre système (Windows, macOS ou Linux).
  2. Installez Android Studio, qui fournit les outils Android et un émulateur de téléphone.
  3. Installez un éditeur de code : Visual Studio Code avec l'extension « Flutter » est un excellent choix.
  4. Vérifiez l'installation en ouvrant un terminal et en tapant :
flutter doctor

Cette commande liste ce qui est prêt et ce qui manque. Corrigez chaque point signalé par une croix avant de continuer, en particulier les licences Android (flutter doctor --android-licenses).

Étape 2 : créer le projet

Dans le dossier de votre choix, lancez :

flutter create mes_taches
cd mes_taches

Flutter génère un projet complet. Le fichier qui nous intéresse est lib/main.dart : c'est le point d'entrée de l'application.

Étape 3 : le code de l'application

Remplacez tout le contenu de lib/main.dart par le code suivant :

import 'package:flutter/material.dart';

void main() {
  runApp(const MesTachesApp());
}

class MesTachesApp extends StatelessWidget {
  const MesTachesApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Mes tâches',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF0A4FA3)),
        useMaterial3: true,
      ),
      home: const EcranTaches(),
    );
  }
}

class Tache {
  Tache(this.titre);

  final String titre;
  bool faite = false;
}

class EcranTaches extends StatefulWidget {
  const EcranTaches({super.key});

  @override
  State<EcranTaches> createState() => _EcranTachesState();
}

class _EcranTachesState extends State<EcranTaches> {
  final List<Tache> _taches = [];
  final TextEditingController _saisie = TextEditingController();

  void _ajouter() {
    final texte = _saisie.text.trim();
    if (texte.isEmpty) return;
    setState(() => _taches.add(Tache(texte)));
    _saisie.clear();
  }

  @override
  void dispose() {
    _saisie.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final restantes = _taches.where((t) => !t.faite).length;
    return Scaffold(
      appBar: AppBar(title: Text('Mes tâches ($restantes à faire)')),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(16),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: _saisie,
                    decoration: const InputDecoration(
                      labelText: 'Nouvelle tâche',
                      border: OutlineInputBorder(),
                    ),
                    onSubmitted: (_) => _ajouter(),
                  ),
                ),
                const SizedBox(width: 12),
                FilledButton(onPressed: _ajouter, child: const Text('Ajouter')),
              ],
            ),
          ),
          Expanded(
            child: _taches.isEmpty
                ? const Center(child: Text('Aucune tâche pour le moment.'))
                : ListView.builder(
                    itemCount: _taches.length,
                    itemBuilder: (context, i) {
                      final tache = _taches[i];
                      return Dismissible(
                        key: ObjectKey(tache),
                        background: Container(color: Colors.red.shade100),
                        onDismissed: (_) => setState(() => _taches.removeAt(i)),
                        child: CheckboxListTile(
                          title: Text(
                            tache.titre,
                            style: TextStyle(
                              decoration: tache.faite
                                  ? TextDecoration.lineThrough
                                  : null,
                            ),
                          ),
                          value: tache.faite,
                          onChanged: (v) =>
                              setState(() => tache.faite = v ?? false),
                        ),
                      );
                    },
                  ),
          ),
        ],
      ),
    );
  }
}

Étape 4 : comprendre le code

Tout est « widget »

En Flutter, chaque élément visible est un widget : un texte, un bouton, une liste, et même l'écran entier. On les imbrique comme des boîtes les unes dans les autres. MaterialApp configure l'application (titre, couleurs), Scaffold fournit la structure d'un écran (barre du haut, contenu).

Widget sans état et widget avec état

MesTachesApp est un StatelessWidget : il ne change jamais. EcranTaches est un StatefulWidget : son contenu évolue quand l'utilisateur agit. Ses données vivent dans la classe _EcranTachesState.

setState : redessiner l'écran

Chaque fois que la liste change (ajout, case cochée, suppression), on modifie les données à l'intérieur de setState(...). Flutter sait alors qu'il doit redessiner l'écran. Oublier setState est l'erreur la plus fréquente du débutant : les données changent, mais rien ne bouge à l'écran.

La saisie

TextEditingController lit le texte tapé dans le champ. La méthode _ajouter ignore les saisies vides, ajoute la tâche puis vide le champ. On libère le contrôleur dans dispose() pour éviter les fuites de mémoire.

La liste

ListView.builder ne construit que les lignes visibles à l'écran : l'application reste fluide même avec des centaines de tâches. Chaque ligne est un CheckboxListTile enveloppé dans un Dismissible, qui gère le glissement pour supprimer.

Étape 5 : lancer l'application

Branchez votre téléphone Android en USB avec le débogage USB activé (dans les options pour les développeurs), ou démarrez un émulateur depuis Android Studio. Puis :

flutter run

Pendant que l'application tourne, modifiez par exemple le texte du bouton et enregistrez le fichier : grâce au hot reload, le changement apparaît en une seconde, sans relancer l'application.

Étape 6 : produire le fichier à installer

Pour obtenir un fichier APK à partager ou installer :

flutter build apk --release

Le fichier se trouve ensuite dans build/app/outputs/flutter-apk/app-release.apk. Pour publier sur Google Play, on produit plutôt un fichier AAB avec flutter build appbundle et on le signe avec sa propre clé : c'est l'objet d'un prochain tutoriel.

Pour aller plus loin

  • Sauvegarder les tâches : pour l'instant, elles disparaissent à la fermeture. Le package shared_preferences permet de les conserver sur le téléphone.
  • Ajouter une date d'échéance et trier les tâches.
  • Synchroniser avec un serveur pour partager la liste entre plusieurs téléphones.

Pour progresser de façon structurée, consultez aussi notre feuille de route pour apprendre à coder et notre guide Git et GitHub pour versionner votre projet.

Questions fréquentes

Faut-il un ordinateur puissant pour développer avec Flutter ?

Un ordinateur récent avec 8 Go de mémoire suffit pour débuter. L'émulateur Android est gourmand : si votre machine est modeste, testez directement sur votre téléphone branché en USB.

Peut-on créer une application iPhone depuis Windows ?

Le code Flutter est le même, mais la compilation et la publication pour iPhone exigent un Mac. Beaucoup de développeurs commencent sur Android depuis Windows, puis utilisent un Mac uniquement pour l'étape iOS.

Quel langage utilise Flutter ?

Flutter utilise Dart, un langage proche de JavaScript et de Java, facile à prendre en main si vous connaissez déjà un langage de programmation.

Flutter est-il gratuit ?

Oui, Flutter est gratuit et open source, y compris pour un usage commercial.

Un projet d'application à réaliser ?

Ce tutoriel montre les bases. Pour une application professionnelle avec comptes utilisateurs, paiement mobile et back-office, l'équipe NEWTIV peut vous accompagner : demandez un devis, nous répondons sous 48 heures ouvrées.