Saltar al contenido principal

Adaptaciones automáticas de plataforma

Aprende más sobre la adaptabilidad de plataforma de Flutter.

Filosofía de adaptación

#

En general, existen dos casos de adaptabilidad a la plataforma:

  1. Cosas que son comportamientos del entorno del sistema operativo (como la edición de texto y el desplazamiento) y que estarían 'mal' si ocurriera un comportamiento diferente.
  2. Cosas que convencionalmente se implementan en aplicaciones utilizando los SDK de los fabricantes (como usar pestañas paralelas en iOS o mostrar un android.app.AlertDialog en Android).

Este artículo cubre principalmente las adaptaciones automáticas proporcionadas por Flutter en el caso 1 en Android e iOS.

Para el caso 2, Flutter incluye los medios para producir los efectos apropiados de las convenciones de la plataforma, pero no se adapta automáticamente cuando se necesitan elecciones de diseño de la aplicación. Para más detalles, consulta el issue #8410 y la definición del problema del widget adaptativo Material/Cupertino.

Para ver un ejemplo de una aplicación que utiliza diferentes estructuras de arquitectura de información en Android e iOS pero comparte el mismo código de contenido, consulta los ejemplos de código de platform_design.

#

Flutter proporciona los patrones de navegación que se ven en Android e iOS y también adapta automáticamente la animación de navegación a la plataforma actual.

#

En Android, la transición predeterminada de Navigator.push() está modelada según startActivity(), que generalmente tiene una variante de animación de abajo hacia arriba.

En iOS:

  • La API predeterminada Navigator.push() produce una transición de estilo Show/Push de iOS que se anima de fin a inicio según la configuración RTL de la configuración regional. La página detrás de la nueva ruta también se desliza con efecto parallax en la misma dirección que en iOS.
  • Existe un estilo de transición independiente de abajo hacia arriba cuando se realiza un push a una ruta de página donde PageRoute.fullscreenDialog es verdadero. Esto representa la transición de estilo Present/Modal de iOS y se utiliza habitualmente en páginas modales a pantalla completa.
Una animación de la transición de página de abajo hacia arriba en Android

Transición de página de Android

Una animación de la transición de página push de estilo fin-inicio en iOS

Transición push de iOS

Una animación de la transición de página present de estilo abajo-hacia-arriba en iOS

Transición present de iOS

Detalles de transición específicos de cada plataforma

#

En Android, Flutter utiliza la animación ZoomPageTransitionsBuilder. Cuando el usuario toca un elemento, la UI se acerca (zoom in) a una pantalla que muestra ese elemento. Cuando el usuario toca para volver atrás, la UI se aleja (zoom out) a la pantalla anterior.

En iOS cuando se utiliza la transición de estilo push, las barras de navegación integradas de Flutter CupertinoNavigationBar y CupertinoSliverNavigationBar animan automáticamente cada subcomponente a su subcomponente correspondiente en la CupertinoNavigationBar o CupertinoSliverNavigationBar de la página siguiente o anterior.

Una animación de la transición de página en Android

Android

Una animación de las transiciones de la barra de navegación durante una transición de página en iOS

Barra de navegación de iOS

Navegación hacia atrás

#

En Android, el botón de volver atrás del SO se envía, por defecto, a Flutter y realiza un pop de la ruta superior del Navigator de WidgetsApp.

En iOS, se puede usar un gesto de deslizar desde el borde para hacer pop de la ruta superior.

Una transición de página activada por el botón de volver atrás de Android

Botón atrás de Android

Una transición de página activada por un gesto de deslizar hacia atrás en iOS

Gesto de deslizar hacia atrás de iOS

Desplazamiento

#

El desplazamiento es una parte importante del aspecto y la sensación de la plataforma, y Flutter ajusta automáticamente el comportamiento de desplazamiento para que coincida con la plataforma actual.

Simulación física

#

Tanto Android como iOS tienen simulaciones físicas de desplazamiento complejas que son difíciles de describir verbalmente. En general, el elemento desplazable de iOS tiene más peso y fricción dinámica, pero Android tiene más fricción estática. Por lo tanto, iOS gana alta velocidad de forma más gradual, pero se detiene de manera menos abrupta y es más resbaladizo a velocidades bajas.

Un impulso suave (fling) donde el elemento desplazable de iOS se deslizó más tiempo a menor velocidad que Android

Comparación de impulso suave

Un impulso (fling) de fuerza media donde el elemento desplazable de Android alcanza la velocidad más rápido y se detiene más abruptamente después de recorrer una distancia más larga

Comparación de impulso medio

Un impulso (fling) fuerte donde el elemento desplazable de Android alcanza la velocidad más rápido y cubre significativamente más distancia

Comparación de impulso fuerte

Comportamiento de overscroll

#

En Android, desplazarse más allá del borde de un elemento desplazable muestra un indicador de resplandor por overscroll (basado en el color del tema Material actual).

En iOS, desplazarse más allá del borde de un elemento desplazable hace overscroll con una resistencia creciente y regresa a su lugar.

Elementos desplazables de Android e iOS impulsados más allá de su borde y mostrando un comportamiento de overscroll específico de la plataforma

Comparación de overscroll dinámico

Elementos desplazables de Android e iOS a los que se aplica overscroll desde una posición de reposo y muestran un comportamiento de overscroll específico de la plataforma

Comparación de overscroll estático

Barras de desplazamiento

#

En plataformas basadas en Material (como Android y web), las barras de desplazamiento suelen ser visibles durante el desplazamiento y pueden permanecer visibles según la plataforma y el tema.

En plataformas basadas en Cupertino (como iOS), las barras de desplazamiento son más minimalistas y generalmente solo aparecen brevemente mientras el usuario se desplaza activamente, desvaneciéndose cuando la interacción se detiene.

Esta diferencia refleja las convenciones visuales de cada plataforma y ayuda a mantener un aspecto y sensación nativos en todos los dispositivos.

Inercia

#

En iOS, los impulsos (flings) repetidos en la misma dirección acumulan inercia y generan más velocidad con cada impulso sucesivo. No hay un comportamiento equivalente en Android.

Impulsos (flings) de desplazamiento repetidos acumulando inercia en iOS

Inercia de desplazamiento en iOS

Volver arriba

#

En iOS, tocar la barra de estado del SO desplaza el controlador de desplazamiento principal hasta la posición superior. No hay un comportamiento equivalente en Android.

Tocar la barra de estado desplaza el elemento desplazable principal de vuelta arriba

Toque en la barra de estado de iOS para volver arriba

Tipografía

#

Al utilizar el paquete Material, la tipografía se ajusta automáticamente por defecto a la familia de fuentes adecuada para la plataforma. Android usa la fuente Roboto. iOS usa la fuente San Francisco.

Al utilizar el paquete Cupertino, el tema predeterminado usa la fuente San Francisco.

La licencia de la fuente San Francisco limita su uso únicamente a software que se ejecute en iOS, macOS o tvOS. Por lo tanto, se utiliza una fuente alternativa (fallback) cuando se ejecuta en Android si la plataforma se invalida en depuración (debug-overridden) a iOS o si se utiliza el tema Cupertino predeterminado.

Puedes optar por adaptar el estilo de texto de los widgets Material para que coincida con el estilo de texto predeterminado en iOS. Puedes ver ejemplos específicos de widgets en la sección Componentes de UI.

Escala tipográfica de la fuente Roboto en Android

Roboto en Android

Escala tipográfica de San Francisco en iOS

San Francisco en iOS

Iconografía

#

Al utilizar el paquete Material, ciertos íconos muestran automáticamente gráficos diferentes según la plataforma. Por ejemplo, los tres puntos del botón de desbordamiento (overflow) son horizontales en iOS y verticales en Android. El botón de volver atrás es un chevron simple en iOS y tiene una flecha con tallo en Android.

Íconos apropiados para Android

Íconos en Android

Íconos apropiados para iOS

Íconos en iOS

La librería Material también proporciona un conjunto de íconos adaptativos para cada plataforma a través de Icons.adaptive.

Respuesta háptica

#

Los paquetes Material y Cupertino activan automáticamente la respuesta háptica adecuada según la plataforma en determinados escenarios.

Por ejemplo, la selección de una palabra mediante la pulsación larga en un campo de texto activa una vibración tipo 'zumbido' en Android y no en iOS.

Desplazarse por los elementos de un selector (picker) en iOS activa un golpe de 'impacto ligero' y ninguna respuesta en Android.

Edición de texto

#

Tanto los campos de entrada de texto de Material como los de Cupertino admiten la revisión ortográfica y se adaptan para utilizar la configuración de revisión ortográfica adecuada para la plataforma, así como el menú de revisión ortográfica y los colores de resaltado adecuados.

Flutter también realiza las siguientes adaptaciones al editar el contenido de los campos de texto para coincidir con la plataforma actual.

Navegación por gestos del teclado

#

En Android, se pueden realizar deslices horizontales en la tecla espacio del teclado virtual para mover el cursor en los campos de texto de Material y Cupertino.

En dispositivos iOS con funciones 3D Touch, se podía realizar un gesto de presionar con fuerza y arrastrar en el teclado virtual para mover el cursor en 2D a través de un cursor flotante. Esto funciona tanto en los campos de texto de Material como en los de Cupertino.

Mover el cursor mediante la tecla de espacio en Android

Movimiento de cursor con tecla de espacio en Android

Mover el cursor arrastrando con 3D Touch en el teclado en iOS

Movimiento de cursor arrastrando con 3D Touch en iOS

Barra de herramientas de selección de texto

#

Con Material en Android, se muestra la barra de herramientas de selección de estilo Android cuando se realiza una selección de texto en un campo de texto.

Con Material en iOS o al usar Cupertino, se muestra la barra de herramientas de selección de estilo iOS cuando se realiza una selección de texto en un campo de texto.

Barra de herramientas de texto apropiada para Android

Barra de herramientas de selección de texto de Android

Barra de herramientas de texto apropiada para iOS

Barra de herramientas de selección de texto de iOS

Gesto de toque único

#

Con Material en Android, un toque único en un campo de texto coloca el cursor en la ubicación del toque.

Una selección de texto colapsada también muestra un controlador arrastrable para mover el cursor posteriormente.

Con Material en iOS o al usar Cupertino, un toque único en un campo de texto coloca el cursor en el borde más cercano de la palabra tocada.

Las selecciones de texto colapsadas no tienen controladores arrastrables en iOS.

Mover el cursor a la posición tocada en Android

Toque en Android

Mover el cursor al borde más cercano de la palabra tocada en iOS

Toque en iOS

Gesto de pulsación larga

#

Con Material en Android, una pulsación larga selecciona la palabra bajo la pulsación larga. La barra de herramientas de selección se muestra al soltar.

Con Material en iOS o al usar Cupertino, una pulsación larga coloca el cursor en la ubicación de la pulsación larga. La barra de herramientas de selección se muestra al soltar.

Seleccionar una palabra con pulsación larga en Android

Pulsación larga en Android

Seleccionar una posición con pulsación larga en iOS

Pulsación larga en iOS

Gesto de arrastre con pulsación larga

#

Con Material en Android, arrastrar mientras se mantiene la pulsación larga expande las palabras seleccionadas.

Con Material en iOS o al usar Cupertino, arrastrar mientras se mantiene la pulsación larga mueve el cursor.

Expandir la selección de palabras con un arrastre tras pulsación larga en Android

Arrastre con pulsación larga en Android

Mover el cursor con un arrastre tras pulsación larga en iOS

Arrastre con pulsación larga en iOS

Gesto de doble toque

#

Tanto en Android como en iOS, un doble toque selecciona la palabra que recibe el doble toque y muestra la barra de herramientas de selección.

Seleccionar una palabra mediante doble toque en Android

Doble toque en Android

Seleccionar una palabra mediante doble toque en iOS

Doble toque en iOS

Componentes de UI

#

Esta sección incluye recomendaciones preliminares sobre cómo adaptar los widgets Material para ofrecer una experiencia natural y atractiva en iOS. Tus comentarios son bienvenidos en el issue #8427.

Widgets con constructores .adaptive()

#

Varios widgets admiten constructores .adaptive(). La siguiente tabla enumera estos widgets. Los constructores adaptativos sustituyen los componentes Cupertino correspondientes cuando la aplicación se ejecuta en un dispositivo iOS.

Los widgets de la siguiente tabla se utilizan principalmente para la entrada, la selección y para mostrar información del sistema. Debido a que estos controles están estrechamente integrados con el sistema operativo, los usuarios están acostumbrados a reconocerlos y responder a ellos. Por lo tanto, te recomendamos seguir las convenciones de la plataforma.

Widget MaterialWidget CupertinoConstructor adaptativo
Switch en Material 3
Switch
Switch en HIG
CupertinoSwitch
Switch.adaptive()
Slider en Material 3
Slider
Slider en HIG
CupertinoSlider
Slider.adaptive()
Circular progress indicator en Material 3
CircularProgressIndicator
Activity indicator en HIG
CupertinoActivityIndicator
CircularProgressIndicator.adaptive()
Refresh indicator en Material 3
RefreshProgressIndicator
Refresh indicator en HIG
CupertinoActivityIndicator
RefreshIndicator.adaptive()
Checkbox en Material 3
Checkbox
Checkbox en HIG
CupertinoCheckbox
Checkbox.adaptive()
Radio en Material 3
Radio
Radio en HIG
CupertinoRadio
Radio.adaptive()
AlertDialog en Material 3
AlertDialog
AlertDialog en HIG
CupertinoAlertDialog
AlertDialog.adaptive()

Barra de aplicaciones superior y barra de navegación

#

Desde Android 12, la UI predeterminada para las barras de aplicaciones superiores sigue las pautas de diseño definidas en Material 3. En iOS, un componente equivalente llamado "Navigation Bars" está definido en las Human Interface Guidelines de Apple (HIG).

Top App Bar en Material 3

Top App Bar en Material 3

Navigation Bar en Human Interface Guidelines

Navigation Bar en Human Interface Guidelines

Ciertas propiedades de las barras de aplicaciones en aplicaciones Flutter se deben adaptar, como los íconos del sistema y las transiciones de página. Estas ya se adaptan automáticamente al usar los widgets Material AppBar y SliverAppBar. También puedes personalizar aún más las propiedades de estos widgets para adaptarlos mejor a los estilos de la plataforma iOS, como se muestra a continuación.

dart
// Map the text theme to iOS styles
TextTheme cupertinoTextTheme = TextTheme(
    headlineMedium: CupertinoThemeData()
        .textTheme
        .navLargeTitleTextStyle
         // fixes a small bug with spacing
        .copyWith(letterSpacing: -1.5),
    titleLarge: CupertinoThemeData().textTheme.navTitleTextStyle)
...

// Use iOS text theme on iOS devices
ThemeData(
      textTheme: Platform.isIOS ? cupertinoTextTheme : null,
      ...
)
...

// Modify AppBar properties
AppBar(
        surfaceTintColor: Platform.isIOS ? Colors.transparent : null,
        shadowColor: Platform.isIOS ? CupertinoColors.darkBackgroundGray : null,
        scrolledUnderElevation: Platform.isIOS ? .1 : null,
        toolbarHeight: Platform.isIOS ? 44 : null,
        ...
      ),

Sin embargo, dado que las barras de aplicaciones se muestran junto a otros contenidos en tu página, solo se recomienda adaptar el estilo mientras sea coherente con el resto de tu aplicación. Puedes ver muestras de código adicionales y una explicación más detallada en la discusión de GitHub sobre adaptaciones de barras de aplicaciones.

Barras de navegación inferiores

#

Desde Android 12, la UI predeterminada para las barras de navegación inferiores sigue las pautas de diseño definidas en Material 3. En iOS, un componente equivalente llamado "Tab Bars" está definido en las Human Interface Guidelines de Apple (HIG).

Bottom Navigation Bar en Material 3

Bottom Navigation Bar en Material 3

Tab Bar en Human Interface Guidelines

Tab Bar en Human Interface Guidelines

Dado que las barras de pestañas son persistentes en toda tu aplicación, deben coincidir con tu propia identidad de marca. Sin embargo, si eliges utilizar el estilo predeterminado de Material en Android, podrías considerar adaptarlo a las barras de pestañas predeterminadas de iOS.

Para implementar barras de navegación inferiores específicas de la plataforma, puedes usar el widget NavigationBar de Flutter en Android y el widget CupertinoTabBar en iOS. A continuación se incluye un fragmento de código que puedes adaptar para mostrar barras de navegación específicas de la plataforma.

dart
final Map<String, Icon> _navigationItems = {
    'Menu': Platform.isIOS ? Icon(CupertinoIcons.house_fill) : Icon(Icons.home),
    'Order': Icon(Icons.adaptive.share),
  };

...

Scaffold(
  body: _currentWidget,
  bottomNavigationBar: Platform.isIOS
          ? CupertinoTabBar(
              currentIndex: _currentIndex,
              onTap: (index) {
                setState(() => _currentIndex = index);
                _loadScreen();
              },
              items: _navigationItems.entries
                  .map<BottomNavigationBarItem>(
                      (entry) => BottomNavigationBarItem(
                            icon: entry.value,
                            label: entry.key,
                          ))
                  .toList(),
            )
          : NavigationBar(
              selectedIndex: _currentIndex,
              onDestinationSelected: (index) {
                setState(() => _currentIndex = index);
                _loadScreen();
              },
              destinations: _navigationItems.entries
                  .map<Widget>((entry) => NavigationDestination(
                        icon: entry.value,
                        label: entry.key,
                      ))
                  .toList(),
            ));

Campos de texto

#

Desde Android 12, los campos de texto siguen las pautas de diseño de Material 3 (M3). En iOS, las Human Interface Guidelines (HIG) de Apple definen un componente equivalente.

Text Field en Material 3

Text Field en Material 3

Text Field en Human Interface Guidelines

Text Field en HIG

Dado que los campos de texto requieren la entrada del usuario, su diseño debe seguir las convenciones de la plataforma.

Para implementar un TextField específico de la plataforma en Flutter, puedes adaptar el estilo del TextField de Material.

dart
Widget _createAdaptiveTextField() {
  final _border = OutlineInputBorder(
    borderSide: BorderSide(color: CupertinoColors.lightBackgroundGray),
  );

  final iOSDecoration = InputDecoration(
    border: _border,
    enabledBorder: _border,
    focusedBorder: _border,
    filled: true,
    fillColor: CupertinoColors.white,
    hoverColor: CupertinoColors.white,
    contentPadding: EdgeInsets.fromLTRB(10, 0, 0, 0),
  );

  return Platform.isIOS
      ? SizedBox(
          height: 36.0,
          child: TextField(
            decoration: iOSDecoration,
          ),
        )
      : TextField();
}

Para aprender más sobre la adaptación de campos de texto, echa un vistazo a la discusión de GitHub sobre campos de texto. Puedes dejar comentarios o hacer preguntas en la discusión.