Saltar al contenido principal

Flutter Widget Previewer

Aprende cómo usar el Flutter Widget Previewer para ver cómo se renderizan tus widgets en tiempo real, de forma independiente a tu aplicación completa.

En esta guía, aprenderás cómo usar el Flutter Widget Previewer.

Resumen

#

Con el Flutter Widget Previewer, puedes ver tus widgets renderizarse en tiempo real, de forma independiente a una app completa, en el navegador Chrome. Para iniciar el previsualizador, mostrar un Widget en él y personalizar una previsualización, consulta las siguientes secciones.

Abrir el previsualizador

#

IDEs

#

A partir de Flutter 3.38, Android Studio, IntelliJ y Visual Studio Code inician automáticamente el Flutter Widget Previewer al abrirse.

Android Studio e IntelliJ

#

Para abrir el Widget Previewer en Android Studio o IntelliJ, abre la pestaña "Flutter Widget Preview" en la barra lateral:

Flutter Widget Previewer en Android Studio

Visual Studio Code

#

Para abrir el Widget Previewer en Visual Studio Code, abre la pestaña "Flutter Widget Preview" en la barra lateral:

Flutter Widget Previewer en Visual Studio Code

Línea de comandos

#

Para iniciar el Flutter Widget Previewer, navega al directorio raíz de tu proyecto de Flutter y ejecuta el siguiente comando en tu terminal. Esto lanzará un servidor local y abrirá un entorno de Widget Preview en Chrome que se actualiza automáticamente según los cambios en tu proyecto.

shell
flutter widget-preview start

Previsualizar un widget

#

Después de haber iniciado el previsualizador, para observar un Widget, debes usar la anotación @Preview definida en package:flutter/widget_previews.dart. Esta anotación se puede aplicar a:

  • Funciones de nivel superior que devuelven un Widget o WidgetBuilder.
  • Métodos estáticos dentro de una clase que devuelven un Widget o WidgetBuilder.
  • Constructores públicos y factories de Widget sin argumentos requeridos.

Aquí tienes un ejemplo básico de cómo usar la anotación @Preview para previsualizar un Widget Text:

dart
import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart'; // For Material widgets

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

Widget de ejemplo en Flutter Widget Previewer Cada instancia de previsualización proporciona varios controles para interactuar con el Widget previsualizado. De izquierda a derecha:

  • Acercar (Zoom in): Amplía el Widget en la previsualización.

  • Alejar (Zoom out): Reduce la ampliación del Widget en la previsualización.

  • Restablecer zoom: Devuelve la previsualización del Widget a su nivel de zoom predeterminado.

  • Alternar entre modo claro y oscuro: Cambia el tema de la previsualización entre un esquema de colores claro y oscuro.

  • Realizar un Hot Restart para la previsualización individual: Reinicia solo la previsualización de Widget específica, lo que permite aplicar cambios rápidamente sin reiniciar toda la aplicación.

Para el caso en que se haya modificado el Estado global (por ejemplo, si se ha cambiado un inicializador estático), se puede indicar a todo el previsualizador de widgets que realice un Hot Restart utilizando el botón en la parte inferior derecha del entorno.

Filtrar previsualizaciones por archivo seleccionado

#

Al ver previsualizaciones dentro de un IDE, el previsualizador de widgets está configurado para filtrar el conjunto de previsualizaciones según el archivo actualmente seleccionado:

Filtrar por previsualizaciones del archivo seleccionado en Flutter Widget Previewer

Para desactivar este comportamiento, desmarca la opción "Filtrar previsualizaciones por archivo seleccionado" en la parte inferior izquierda del entorno.

Personalizar una previsualización

#

La anotación @Preview tiene varios parámetros que puedes usar para personalizar la previsualización:

  • name: Un nombre descriptivo para la previsualización.

  • group: Un nombre utilizado para agrupar previsualizaciones relacionadas en el previsualizador de widgets.

  • size: Restricciones de tamaño artificiales utilizando un objeto Size.

  • textScaleFactor: Una escala de fuente personalizada.

  • wrapper: Una función que envuelve tu Widget previsualizado en un árbol de widgets específico (por ejemplo, para inyectar el Estado de la aplicación en el árbol de widgets con un InheritedWidget).

  • theme: Una función para proporcionar datos de temas de Material y Cupertino.

  • brightness: El brillo inicial del tema.

  • localizations: Una función para aplicar una configuración de localización.

Crear anotaciones de previsualización personalizadas

#

Para reducir la cantidad de código repetitivo necesario para definir previsualizaciones con un conjunto común de propiedades, la clase de anotación Preview se puede extender para crear anotaciones de previsualización personalizadas adaptadas a tu proyecto.

Aquí tienes un ejemplo de una anotación de previsualización personalizada que proporciona datos de temas:

dart
final class MyCustomPreview extends Preview {
  const MyCustomPreview({
    super.name,
    super.group,
    super.size,
    super.textScaleFactor,
    super.wrapper,
    super.brightness,
    super.localizations,
  }) : super(theme: MyCustomPreview.themeBuilder);

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

Extender la clase de anotación Preview también permite sobrescribir el método Preview.transform() . Este método es invocado por el previsualizador de widgets y se puede usar para modificar la previsualización en tiempo de ejecución, lo que permite configuraciones de previsualización que de otro modo no serían posibles en un contexto const:

dart
final class TransformativePreview extends Preview {
  const TransformativePreview({
    super.name,
    super.group,
    super.size,
    super.textScaleFactor,
    super.wrapper,
    super.brightness,
    super.localizations,
  });

  // Note: this is no longer public or static as it's injected
  // at runtime when transform() is invoked.
  PreviewThemeData _themeBuilder() {
    return PreviewThemeData(
      materialLight: ThemeData.light(),
      materialDark: ThemeData.dark(),
    );
  }

  @override
  Preview transform() {
    final originalPreview = super.transform();
    // Create's a PreviewBuilder that can be used to modify
    // the preview contents.
    final builder = originalPreview.toBuilder();
    builder
      ..name = 'Transformed - ${originalPreview.name}'
      ..theme = _themeBuilder;

    // Return the updated Preview instance.
    return builder.toPreview();
  }
}

Crear múltiples configuraciones de previsualización

#

Crear múltiples previsualizaciones con diferentes configuraciones puede ser tan simple como aplicar múltiples anotaciones @Preview a una sola función o constructor:

dart
@Preview(
  group: 'Brightness',
  name: 'Example - light',
  brightness: Brightness.light,
)
@Preview(
  group: 'Brightness',
  name: 'Example - dark',
  brightness: Brightness.dark,
)
Widget buttonPreview() => const ButtonShowcase();

Múltiples previsualizaciones en Flutter Widget Previewer

Para simplificar la creación de múltiples previsualizaciones con configuraciones comunes, puedes extender la clase MultiPreview para crear una anotación personalizada que cree múltiples previsualizaciones. El siguiente MultiPreview crea las mismas dos previsualizaciones que el ejemplo anterior:

dart
/// Creates light and dark mode previews.
final class MultiBrightnessPreview extends MultiPreview {
  const MultiBrightnessPreview();

  @override
  List<Preview> get previews => const [
        Preview(
          group: 'Brightness',
          name: 'Example - light',
          brightness: Brightness.light,
        ),
        Preview(
          group: 'Brightness',
          name: 'Example - dark',
          brightness: Brightness.dark,
        ),
      ];
}

@MultiBrightnessPreview()
Widget buttonPreview() => const ButtonShowcase();

Al igual que Preview, MultiPreview también proporciona un método MultiPreview.transform() para realizar transformaciones en cada previsualización en tiempo de ejecución:

dart
/// Creates light and dark mode previews.
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'
        // Building names based on values provided to the annotation
        // isn't possible within a constant constructor. However,
        // there's no such restriction when building a Preview at
        // runtime.
        ..name = '$name - ${preview.brightness!.name}';
      return builder.toPreview();
    }).toList();
  }
}

@MultiBrightnessPreview(name: 'Example')
Widget buttonPreview() => const ButtonShowcase();

Restricciones y limitaciones

#

El Flutter Widget Previewer tiene ciertas restricciones que debes tener en cuenta:

  • Nombres de callbacks públicos: Todos los argumentos de callback proporcionados a las anotaciones de previsualización deben ser públicos y constantes. Esto es necesario para que la implementación de generación de código del previsualizador funcione correctamente.

  • APIs no soportadas: Los plugins nativos y cualquier API de las librerías dart:io o dart:ffi no están soportados. Esto se debe a que el previsualizador de widgets está construido con Flutter Web, que no tiene acceso a las APIs de la plataforma nativa subyacente. Aunque los plugins web pueden funcionar al usar Chrome, no hay garantía de que funcionen dentro de otros entornos, como cuando están integrados en IDEs.

    Los widgets con dependencias transitivas en dart:io o dart:ffi se cargarán correctamente, pero todas las APIs de estas librerías lanzarán una excepción cuando se invoquen.

    Consulta la documentación de Dart sobre importaciones condicionales para obtener detalles sobre cómo estructurar tu aplicación para admitir limpiamente librerías específicas de la plataforma al dirigirse a múltiples plataformas.

  • Rutas de assets: Al usar APIs fromAsset de dart:ui para cargar recursos, debes usar rutas basadas en paquetes en lugar de rutas locales directas. Esto garantiza que los assets se puedan ubicar y cargar correctamente dentro del entorno web del previsualizador. Por ejemplo, usa 'packages/my_package_name/assets/my_image.png' en lugar de 'assets/my_image.png'.

  • Widgets sin restricciones (unconstrained): Los widgets sin restricciones son restringidos automáticamente a aproximadamente la mitad de la altura y el ancho del previsualizador de widgets. Es probable que este comportamiento cambie en el futuro, por lo que las restricciones deben aplicarse usando el parámetro size cuando sea posible.

  • Soporte multiproyecto en IDEs: El previsualizador de widgets actualmente solo admite mostrar previsualizaciones contenidas dentro de un solo proyecto o espacio de trabajo de Pub. Estamos investigando activamente opciones para admitir sesiones de IDE con múltiples proyectos de Flutter (#173550).