El scroll es mostrar contenido más grande que la pantalla.
Seguro que haciendo pruebas en el módulo anterior te pasó. Añadiste un texto demasiado largo a una columna, o probaste tu App en un móvil más pequeño, y de repente… ¡Boom!
La pantalla se rompe, aparece una franja amarilla y negra de “zona de peligro” y la consola te grita: RenderFlex overflowed by 350 pixels.
Esto ocurre porque, por defecto, los layouts como Column o Row no tienen scroll. Si el contenido no cabe, Flutter no lo recorta ni lo esconde: te avisa de que hay un error de diseño.
Hoy vamos a ver la solución más sencilla: el SingleChildScrollView.
Qué es SingleChildScrollView
Es el widget de scroll más básico. Su funcionamiento es simple: toma un único hijo (child) y, si ese hijo es más grande que la pantalla, permite deslizarlo para ver el resto.
Imagínalo como una ventana. Si el paisaje (el contenido) es más grande que el marco de la ventana, este widget te permite mover el paisaje para verlo todo.
Implementación básica
Supongamos que tenemos una Column con muchos textos que da error. La solución es tan simple como “envolver” (Wrap) esa columna.
Scaffold(
body: SingleChildScrollView(
// Solo admite un hijo. Generalmente será una Column.
child: Column(
children: [
Container(height: 300, color: Colors.red),
Container(height: 300, color: Colors.green),
Container(height: 300, color: Colors.blue),
// Sin scroll, esto daría error porque 900px > altura pantalla
],
),
),
)
Nota: SingleChildScrollView no funciona bien si lo metes dentro de un padre que no tiene altura definida (como otra Column sin Expanded). Necesita tener límites para saber cuándo empezar a hacer scroll.
Dirección del scroll
Por defecto, el scroll es vertical. Pero, ¿y si queremos una fila de tarjetas que se deslicen lateralmente?
Podemos cambiar la propiedad scrollDirection.
SingleChildScrollView(
scrollDirection: Axis.horizontal, // Scroll lateral
child: Row( // Ojo: Ahora el hijo suele ser una Row
children: [
TarjetaProducto(),
TarjetaProducto(),
TarjetaProducto(),
// ...
],
),
)
Comportamiento del scroll
Un detalle que demuestra calidad en una App es cómo se “siente” el scroll. Flutter intenta imitar el comportamiento nativo de cada plataforma, pero podemos forzarlo.
La propiedad physics controla esto:
BouncingScrollPhysics: permite sobrepasar visualmente el límite y volver con un rebote.ClampingScrollPhysics: impide que la posición supere los límites del contenido.
Puedes fijar una física concreta si el diseño lo necesita, aunque normalmente conviene respetar el comportamiento configurado para la plataforma.
SingleChildScrollView(
physics: BouncingScrollPhysics(), // Rebote en Android y iOS
child: Column(...),
)
Controlar la posición con ScrollController
A veces necesitamos controlar el scroll por código:
- Volver arriba al pulsar un botón.
- Saber si el usuario ha llegado al final para cargar más datos.
- Animar la posición.
Para esto usamos un ScrollController.
class MiPantallaConScroll extends StatefulWidget {
@override
_MiPantallaState createState() => _MiPantallaState();
}
class _MiPantallaState extends State<MiPantallaConScroll> {
// 1. Crear el controlador
final ScrollController _scrollController = ScrollController();
void _subirArriba() {
// 3. Usar el controlador para movernos
_scrollController.animateTo(
0, // Posición 0 (el inicio)
duration: Duration(milliseconds: 500),
curve: Curves.easeInOut,
);
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
controller: _scrollController, // 2. Asignarlo al widget
child: Column(children: List.generate(50, (i) => Text("Item $i"))),
),
floatingActionButton: FloatingActionButton(
onPressed: _subirArriba,
child: Icon(Icons.arrow_upward),
),
);
}
}
Rendimiento
SingleChildScrollView es fantástico para formularios, pantallas de configuración o “Acerca de”, donde el contenido es limitado.
Pero tiene un gran defecto, Renderiza todo su contenido de golpe, aunque no esté visible en pantalla.
Si metes una lista de 1.000 fotos en un SingleChildScrollView, Flutter intentará pintar las 1.000 fotos en memoria al mismo tiempo, incluso si el usuario solo está viendo las 2 primeras.
Consecuencias:
- La App tardará en abrir esa pantalla.
- Consumo excesivo de memoria RAM.
- Posible cierre inesperado (Crash) en móviles gama baja.