flutter-add-widget-preview

Ajoute des aperçus de widgets interactifs au projet en utilisant le système previews.dart. À utiliser lors de la création de nouveaux composants UI ou de la mise à jour des écrans existants pour assurer un design cohérent et des tests interactifs.

npx skills add https://github.com/flutter/skills --skill flutter-add-widget-preview

Aperçu des widgets Flutter

Contenu

Directives d'aperçu

Utilisez Flutter Widget Previewer pour afficher les widgets en temps réel, isolés du contexte complet de l'application.

  • Éléments cibles : Appliquez l'annotation @Preview à des fonctions de haut niveau, des méthodes statiques dans une classe, ou des constructeurs/factories de widgets publics sans arguments obligatoires qui retournent un Widget ou WidgetBuilder.
  • Imports : Importez toujours package:flutter/widget_previews.dart pour accéder aux annotations d'aperçu.
  • Annotations personnalisées : Étendez la classe Preview pour créer des annotations personnalisées qui injectent des propriétés communes (par exemple, thèmes, wrappers) sur plusieurs widgets.
  • Configurations multiples : Appliquez plusieurs annotations @Preview à une seule cible pour générer plusieurs instances d'aperçu. Vous pouvez également étendre MultiPreview pour encapsuler les configurations multi-aperçu communes.
  • Transformations à l'exécution : Surchargez la méthode transform() dans les classes Preview ou MultiPreview personnalisées pour modifier dynamiquement les configurations d'aperçu à l'exécution (par exemple, générer des noms basés sur des valeurs dynamiques, ce qui est impossible dans un contexte const).

Gestion des limitations

Respectez les contraintes suivantes lors de la création de widgets pouvant être prévisualisés, car Widget Previewer s'exécute dans un environnement web :

  • Pas d'API natives : N'utilisez pas de plugins natifs ni d'API de dart:io ou dart:ffi. Les widgets ayant des dépendances transitives sur dart:io ou dart:ffi lanceront des exceptions lors de l'invocation. Utilisez des imports conditionnels pour les simuler ou les contourner en mode aperçu.
  • Chemins d'assets : Utilisez des chemins basés sur les packages pour les assets chargés via les API fromAsset de dart:ui (par exemple, packages/my_package_name/assets/my_image.png au lieu de assets/my_image.png).
  • Callbacks publics : Assurez-vous que tous les arguments de callback fournis aux annotations d'aperçu sont publics et constants pour satisfaire les exigences de la génération de code.
  • Contraintes : Appliquez des contraintes explicites en utilisant le paramètre size dans l'annotation @Preview si votre widget n'est pas contraint, car l'aperçu les contraint par défaut à environ la moitié de la fenêtre d'affichage.

Workflows

Créer un aperçu de widget

Copiez et suivez cette liste de contrôle lors de la mise en œuvre d'un nouvel aperçu de widget :

  • [ ] Importez package:flutter/widget_previews.dart.
  • [ ] Identifiez une cible valide (fonction de haut niveau, méthode statique, ou constructeur public sans paramètres).
  • [ ] Appliquez l'annotation @Preview à la cible.
  • [ ] Configurez les paramètres d'aperçu (name, group, size, theme, brightness, etc.) selon les besoins.
  • [ ] Si vous appliquez la même configuration à plusieurs widgets, extrayez la configuration dans une classe personnalisée étendant Preview.

Interaction avec les aperçus

Suivez le workflow conditionnel approprié pour lancer et interagir avec Widget Previewer :

Si vous utilisez un IDE supporté (Android Studio, IntelliJ, VS Code avec Flutter 3.38+) :

  1. Lancez l'IDE. Widget Previewer démarre automatiquement.
  2. Ouvrez l'onglet "Flutter Widget Preview" dans la barre latérale.
  3. Activez "Filter previews by selected file" en bas à gauche si vous souhaitez afficher les aperçus en dehors du fichier actuellement actif.

Si vous utilisez la ligne de commande :

  1. Accédez au répertoire racine du projet Flutter.
  2. Exécutez flutter widget-preview start.
  3. Consultez l'environnement Chrome ouvert automatiquement.

Boucle de rétroaction : Itération d'aperçu

  1. Modifiez le code du widget ou la configuration d'aperçu.
  2. Observez la mise à jour automatique dans Widget Previewer.
  3. Si l'état global (par exemple, les initialiseurs statiques) a été modifié : Cliquez sur le bouton de redémarrage à chaud global en bas à droite.
  4. Si seul l'état local du widget doit être réinitialisé : Cliquez sur le bouton de redémarrage à chaud individuel sur la carte d'aperçu spécifique.
  5. Examinez les erreurs dans la console IDE/CLI -> corrigez -> répétez.

Exemples

Aperçu basique

import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart';

@Preview(name: 'My Sample Text', group: 'Typography')
Widget mySampleText() {
  return const Text('Hello, World!');
}

Aperçu personnalisé avec transformation à l'exécution

import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart';

final class TransformativePreview extends Preview {
  const TransformativePreview({
    super.name,
    super.group,
  });

  PreviewThemeData _themeBuilder() {
    return PreviewThemeData(
      materialLight: ThemeData.light(),
      materialDark: ThemeData.dark(),
    );
  }

  @override
  Preview transform() {
    final originalPreview = super.transform();
    final builder = originalPreview.toBuilder();

    builder
      ..name = 'Transformed - ${originalPreview.name}'
      ..theme = _themeBuilder;

    return builder.toPreview();
  }
}

@TransformativePreview(name: 'Custom Themed Button')
Widget myButton() => const ElevatedButton(onPressed: null, child: Text('Click'));

Implémentation MultiPreview

import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart';

/// Crée automatiquement des aperçus en mode clair et sombre.
final class MultiBrightnessPreview extends MultiPreview {
  const MultiBrightnessPreview({required this.name});

  final String name;

  @override
  List<Preview> get previews => const [
        Preview(brightness: Brightness.light),
        Preview(brightness: Brightness.dark),
      ];

  @override
  List<Preview> transform() {
    final previews = super.transform();
    return previews.map((preview) {
      final builder = preview.toBuilder()
        ..group = 'Brightness'
        ..name = '$name - ${preview.brightness!.name}';
      return builder.toPreview();
    }).toList();
  }
}

@MultiBrightnessPreview(name: 'Primary Card')
Widget cardPreview() => const Card(child: Padding(padding: EdgeInsets.all(8.0), child: Text('Content')));