Los widgets básicos son los bloques de construcción fundamentales para crear interfaces de usuario. En Flutter, todo es un widget, desde un simple texto hasta layouts complejos.
Flutter ofrece widgets que se dividen en dos categorías principales según su capacidad de tener elementos hijos:
Estos widgets no contienen otros widgets dentro de ellos y se usan principalmente para espaciado, separación o indicadores.
Define un espacio de tamaño fijo. Es el widget más eficiente para crear espacios.
SizedBox(
height: 20, // Espacio vertical
width: 100, // Espacio horizontal
)
// Solo altura
SizedBox(height: 20)
// Solo ancho
SizedBox(width: 50) Crea un espacio flexible que se expande para llenar el espacio disponible.
Row(
children: [
Text('Inicio'),
Spacer(), // Empuja el siguiente widget al final
Text('Final'),
],
) Muestra una línea horizontal para separar contenido visualmente.
Column(
children: [
Text('Elemento 1'),
Divider(
color: Colors.grey,
thickness: 1,
indent: 20, // Margen izquierdo
endIndent: 20, // Margen derecho
),
Text('Elemento 2'),
],
) Similar a Divider, pero muestra una línea vertical.
Row(
children: [
Text('Izquierda'),
VerticalDivider(
color: Colors.blue,
thickness: 2,
width: 20,
),
Text('Derecha'),
],
) Indicador de carga circular que no requiere un hijo.
CircularProgressIndicator(
color: Colors.blue,
strokeWidth: 4.0,
)
// Con valor específico (0.0 a 1.0)
CircularProgressIndicator(
value: 0.7, // 70% completado
color: Colors.green,
) Indicador de progreso lineal sin hijos.
LinearProgressIndicator(
color: Colors.blue,
backgroundColor: Colors.grey[300],
)
// Con progreso específico
LinearProgressIndicator(
value: 0.5, // 50% completado
color: Colors.orange,
) A continuación, se muestra un ejemplo práctico que combina varios widgets sin hijos para crear una lista con espaciado y separadores.
class WidgetsSinHijos extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Widgets Sin Hijos')),
body: Column(
children: [
Text('Inicio de la lista'),
SizedBox(height: 20), // Espacio fijo
Divider(), // Línea divisoria
CircularProgressIndicator(), // Indicador de carga
SizedBox(height: 20),
LinearProgressIndicator(value: 0.6),
Spacer(), // Espacio flexible
Text('Final de la lista'),
],
),
);
}
} Estos widgets pueden contener otros widgets y se usan para organizar y estructurar la interfaz.
Organiza sus hijos en una columna vertical.
Column(
mainAxisAlignment: MainAxisAlignment.center, // Alineación vertical
crossAxisAlignment: CrossAxisAlignment.start, // Alineación horizontal
children: [
Text('Elemento 1'),
Text('Elemento 2'),
Text('Elemento 3'),
],
) Organiza sus hijos en una fila horizontal.
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, // Distribución horizontal
crossAxisAlignment: CrossAxisAlignment.center, // Alineación vertical
children: [
Icon(Icons.home),
Text('Inicio'),
Icon(Icons.arrow_forward),
],
) El widget más versátil. Puede contener un hijo y aplicar decoración, padding, margin, etc.
Container(
width: 200,
height: 100,
padding: EdgeInsets.all(16),
margin: EdgeInsets.symmetric(vertical: 8),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.3),
spreadRadius: 2,
blurRadius: 5,
),
],
),
child: Text(
'Contenido',
style: TextStyle(color: Colors.white),
),
) Permite apilar widgets unos sobre otros.
Stack(
children: [
Container(
width: 200,
height: 200,
color: Colors.blue,
),
Positioned(
top: 20,
right: 20,
child: Icon(
Icons.star,
color: Colors.yellow,
size: 30,
),
),
Positioned(
bottom: 10,
left: 10,
child: Text(
'Superpuesto',
style: TextStyle(color: Colors.white),
),
),
],
) Organiza sus hijos en filas o columnas, envolviendo a la siguiente línea cuando es necesario.
Wrap(
spacing: 8.0, // Espacio horizontal entre elementos
runSpacing: 4.0, // Espacio vertical entre filas
children: [
Chip(label: Text('Flutter')),
Chip(label: Text('Dart')),
Chip(label: Text('Mobile')),
Chip(label: Text('Development')),
Chip(label: Text('Cross-platform')),
],
) class LayoutCompleto extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Layout con Widgets Básicos'),
backgroundColor: Colors.blue,
),
body: Column(
children: [
// Header con Row
Container(
padding: EdgeInsets.all(16),
color: Colors.grey[100],
child: Row(
children: [
Icon(Icons.person, color: Colors.blue),
SizedBox(width: 12),
Text(
'Perfil de Usuario',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
Spacer(),
Icon(Icons.settings),
],
),
),
Divider(),
// Contenido principal con Stack
Expanded(
child: Stack(
children: [
Container(
width: double.infinity,
color: Colors.blue[50],
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(),
SizedBox(height: 20),
Text('Cargando contenido...'),
],
),
),
// Botón flotante personalizado
Positioned(
bottom: 20,
right: 20,
child: Container(
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(30),
),
child: IconButton(
icon: Icon(Icons.add, color: Colors.white),
onPressed: () {},
),
),
),
],
),
),
// Footer con Wrap
Container(
padding: EdgeInsets.all(16),
child: Wrap(
spacing: 8,
children: [
Chip(label: Text('Tag 1')),
Chip(label: Text('Tag 2')),
Chip(label: Text('Tag 3')),
],
),
),
],
),
);
}
} Controla la alineación en el eje principal (vertical para Column, horizontal para Row):
MainAxisAlignment.start - Al inicioMainAxisAlignment.center - Al centroMainAxisAlignment.end - Al finalMainAxisAlignment.spaceEvenly - Espacio uniformeMainAxisAlignment.spaceBetween - Espacio entre elementosMainAxisAlignment.spaceAround - Espacio alrededor de elementosControla la alineación en el eje transversal:
CrossAxisAlignment.start - Al inicioCrossAxisAlignment.center - Al centroCrossAxisAlignment.end - Al finalCrossAxisAlignment.stretch - Estirar para llenarTip de rendimiento: Usa SizedBox en lugar de Container vacío para espaciado. Es más eficiente y consume menos recursos.
Combina estos widgets básicos para crear layouts complejos. Domina Column, Row y Container antes de avanzar a widgets más especializados.
A continuación, se presentan algunas buenas prácticas para utilizar widgets básicos de layout en Flutter:
// Usa constantes para espaciado consistente
class AppSpacing {
static const double small = 8.0;
static const double medium = 16.0;
static const double large = 24.0;
}
// Uso
SizedBox(height: AppSpacing.medium) Crea widgets personalizados para reutilizar en diferentes partes de la aplicación. Esto mejora la mantenibilidad y reduce la duplicación de código.
class CustomCard extends StatelessWidget {
final String title;
final Widget child;
const CustomCard({
Key? key,
required this.title,
required this.child,
}) : super(key: key);
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(AppSpacing.small),
padding: EdgeInsets.all(AppSpacing.medium),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
spreadRadius: 1,
blurRadius: 3,
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: AppSpacing.small),
child,
],
),
);
}
}