AlertDialog scrollable (Ya no está depreciado)
AlertDialog debería hacer scroll automáticamente cuando se desborda.
Resumen
#Un AlertDialog ahora hace scroll automáticamente cuando se desborda.
Contexto
#Antes de este cambio,
cuando el contenido del widget de un AlertDialog era demasiado alto,
la pantalla se desbordaba, lo que provocaba que el contenido se recortara.
Esto dio lugar a los siguientes problemas:
- No había forma de ver la parte del contenido que quedaba recortada.
- La mayoría de los alert dialogs tienen botones debajo del contenido para solicitar acciones a los usuarios. Si el contenido se desbordaba, ocultando los botones, los usuarios podrían no percatarse de su existencia.
Descripción del cambio
#El enfoque anterior listaba consecutivamente los widgets de título y contenido
en un widget Column.
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
if (title != null)
Padding(
padding: titlePadding ?? EdgeInsets.fromLTRB(24, 24, 24, content == null ? 20 : 0),
child: DefaultTextStyle(
style: titleTextStyle ?? dialogTheme.titleTextStyle ?? theme.textTheme.title,
child: Semantics(
child: title,
namesRoute: true,
container: true,
),
),
),
if (content != null)
Flexible(
child: Padding(
padding: contentPadding,
child: DefaultTextStyle(
style: contentTextStyle ?? dialogTheme.contentTextStyle ?? theme.textTheme.subhead,
child: content,
),
),
),
// ...
],
);
El nuevo enfoque envuelve ambos widgets en un
SingleChildScrollView por encima de la barra de botones,
haciendo que ambos widgets formen parte del mismo scrollable
y exponiendo la barra de botones en la parte inferior del diálogo.
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
if (title != null || content != null)
SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
if (title != null)
titleWidget,
if (content != null)
contentWidget,
],
),
),
// ...
],
),
Guía de migración
#Podrías ver los siguientes problemas como resultado de este cambio:
- Las pruebas de Semantics podrían fallar debido a la adición de un
SingleChildScrollView. -
Las pruebas manuales de las funciones
TalkbackyVoiceOverdemuestran que siguen exhibiendo el mismo comportamiento (correcto) que antes. - Las pruebas golden podrían fallar.
-
Este cambio podría haber causado diferencias en pruebas golden (que antes pasaban), dado que el
SingleChildScrollViewahora anida los widgets de título y contenido. Algunos proyectos de Flutter han optado por crear pruebas de Semantics tomando capturas golden de los nodos de Semantics utilizados en la compilación de depuración de Flutter.
Cualquier actualización de golden de Semantics que refleje la adición del contenedor de desplazamiento es esperada y estas diferencias deberían ser seguras de aceptar.Ejemplo del árbol de Semantics resultante:
flutter: ├─SemanticsNode#30 <-- SingleChildScrollView
flutter: │ flags: hasImplicitScrolling
flutter: │ scrollExtentMin: 0.0
flutter: │ scrollPosition: 0.0
flutter: │ scrollExtentMax: 0.0
flutter: │
flutter: ├─SemanticsNode#31 <-- title
flutter: │ flags: namesRoute
flutter: │ label: "Hello"
flutter: │
flutter: └─SemanticsNode#32 <-- contents
flutter: label: "Huge content"
- Podrían producirse cambios de diseño (layout) debido a la vista de desplazamiento.
-
Si el diálogo ya se estaba desbordando, este cambio corrige el problema. Este cambio de diseño es esperado.
UnSingleChildScrollViewanidado enAlertDialog.contentdebería funcionar correctamente si se deja en el código, pero debería eliminarse si no es intencionado, ya que podría causar confusión.
Código antes de la migración:
AlertDialog(
title: Text(
'Very, very large title that is also scrollable',
textScaleFactor: 5,
),
content: SingleChildScrollView( // won't be scrollable
child: Text('Scrollable content', textScaleFactor: 5),
),
actions: <Widget>[
TextButton(child: Text('Button 1'), onPressed: () {}),
TextButton(child: Text('Button 2'), onPressed: () {}),
],
)
Código después de la migración:
AlertDialog(
title: Text('Very, very large title', textScaleFactor: 5),
content: Text('Very, very large content', textScaleFactor: 5),
actions: <Widget>[
TextButton(child: Text('Button 1'), onPressed: () {}),
TextButton(child: Text('Button 2'), onPressed: () {}),
],
)
Timeline
#Lanzado en la versión: 1.16.3
En versión estable: 1.17
Referencias
#Doc de diseño:
Documentación de la API:
Problema relevante:
PRs relevantes:
A menos que se indique lo contrario, la documentación de este sitio refleja Flutter 3.44.0. Página actualizada por última vez el 2026-05-05. Ver código fuente oreportar un problema.