Widget DataTable en Flutter

- 👤 Andrés Cruz

🇺🇸 In english

Widget DataTable en Flutter

Cuando empecé a trabajar con DataTable en Flutter, lo primero que descubrí es que este widget es ideal para mostrar información tabular de manera ordenada y visualmente clara. Es la clásica tabla con filas y columnas, pero adaptada al ecosistema Material.

Recuerda que queramos en que creamos un menú lateral en Flutter.

1. Qué es DataTable en Flutter y para qué sirve

Un DataTable es un componente de interfaz de usuario que se utiliza para mostrar datos en forma de tabla. Por lo general, se utiliza en aplicaciones web o móviles para presentar datos en una cuadrícula con filas y columnas interactivas. Los usuarios pueden interactuar con un DataTable para ordenar, buscar, filtrar y paginar datos de gran volumen, lo que hace que sea una herramienta útil para presentar información de manera clara y fácilmente accesible. En resumen, un DataTable es un elemento de la interfaz de usuario que se utiliza para mostrar datos en una tabla interactiva.

Un DataTable Flutter permite:

  • Ordenar columnas
  • Resaltar filas
  • Añadir íconos de edición
  • Integrar texto, imágenes, botones y cualquier widget
  • Desplegar tablas sencillas o complejas

Aunque funciona genial como tabla estática, no siempre es adaptable por defecto en móviles, especialmente cuando la tabla tiene varias columnas. Por eso, es clave entender cómo combinarla con otros widgets para obtener la mejor experiencia.

2. Cómo crear tu primera DataTable (ejemplo práctico)

Vamos a presentar un widget en flutter de lo más útil que es el de DataTable, para presentar datos de manera organizada en un grid o tabla en flutter; para presentar información y esta información puede ser texto, imágenes, botones que en resumen son widgets; vamos a presentar todo el código del ejemplo que vamos a analizar:

DataTable(
  sortColumnIndex: 2,
  sortAscending: false,
  columns: [
    DataColumn(label: Text("Nombre")),
    DataColumn(label: Text("Apellido")),
    DataColumn(label: Text("Años"), numeric: true),
  ],
  rows: [
    DataRow(
      selected: true,
      cells: [
        DataCell(Text("Andrés"), showEditIcon: true),
        DataCell(Text("Cruz")),
        DataCell(Text("28")),
      ],
    ),
    DataRow(
      cells: [
        DataCell(Text("Ramos")),
        DataCell(Text("Ayu")),
        DataCell(Text("999")),
      ],
    ),
  ],
)

Con esto logramos una sencilla tabla como la siguiente:

Datatable Flutter

Como bien sabrás si también eres desarrollador web o también haz intentado emplear los grid en plataformas móviles; los grid no son adaptativos, lo que hace que la visualización de los datos sea complicada; pero con este widget podemos emplearlo en conjunto con otros que inclusive nos permitirá crear scroll de manera horizontal, etc.

Cuando lo probé por primera vez, noté dos cosas:

  • El showEditIcon solo dibuja el ícono, no hace editable la celda (yo también pensé que editaba).
  • Marcar selected: true hace que la fila se resalte con un gris suave, útil para feedback visual.

Configurar una DataTable en flutter

La tabla o Datatable en su mínima configuración necesita de definir el DataColumn para definir el label de las columnas y los DataRow que son para definir la data dentro de la propiedad rows (además del propio DataTable claro está); lo que tienes que tener en cuenta es que debe definir los mismos DataColumn que los DataCell dentro de un DataRow.

Existen múltiples propiedades que puedes emplear a gusto para personalizar las columnas, filas, celdas o la misma tabla; veamos algunas de las principales:

Fila seleccionada

Mediante el selected en el DataRow podrás indicar que quieres resaltar una fila en cuestión, la que aparecerá con un suave gris tal cual puedes ver en la imagen anterior.

Celda editable

Mediante el showEditIcon en el DataCell podrás especificar un ícono de un lápiz para indicar que la celda en cuestión puede ser editable, aunque esto no significa que dicho atributo implementa la edición en la celda; lo único que hace es dibujar dicho ícono.

Ordenamiento

También podemos establecer íconos representativos para mostrar que una columnas pueda ser ordenada; para eso podemos indicar el índice de la columna que deseas ordenar sortColumnIndex e indicar si quieres mostrar el ícono para ordenar de manera ascendente o no sortAscending.

3. Propiedades esenciales del widget DataTable

  • DataColumn
    • Aquí defines las columnas. Lo importante es mantener coherencia: si tienes 3 DataColumn, tus DataRow deben tener 3 DataCell.
  • DataRow
    • Cada fila de la tabla. Algo que aprendí experimentando es que puedes resaltar una fila usando selected: true para dar contexto al usuario.
  • DataCell
    • Cada celda de la fila. Aquí puedes colocar casi cualquier widget.
      El atributo showEditIcon: true muestra el lápiz, pero no implementa la edición (tienes que hacerlo tú).
  • Ordenamiento (sort)
    • Cuando estaba configurando el ordenamiento, tuve que jugar con:
      • sortColumnIndex
      • sortAscending

Esto permite que Flutter muestre el icono de orden en el encabezado y aplique tu lógica de sorting.

4. Cómo hacer una DataTable responsive en Flutter

Uno de los primeros obstáculos que tuve fue que los DataTable no se adaptan bien por defecto en móviles, especialmente cuando hay muchas columnas.

Aquí van las soluciones más prácticas:

Scroll horizontal

La más simple y efectiva:

SingleChildScrollView(
 scrollDirection: Axis.horizontal,
 child: DataTable(...),
)

Esta es una forma de evitar que las columnas se cortaran en pantallas pequeñas.

Ajuste de columnas

Puedes envolver el contenido en FittedBox, o ajustar el Text con softWrap y overflow. Depende del nivel de densidad que quieras en tu tabla.

Buenas prácticas

  • Evita más de 5 columnas en móvil
  • Usa abreviaturas cuando sea necesario
  • Prueba siempre en landscape y portrait
  • Estas en Flutter, todo es reactivo, detecta el tamaño de la pantalla y adapta la cantidad de filas

5. Optimización: cómo manejar tablas con muchos datos

El DataTable no es eficiente para miles de filas, porque renderiza todo al mismo tiempo.

Aquí van algunas consideraciones:

  • Paginación
    • Empieza a dividir las filas en páginas para que Flutter no tenga que renderizarlo todo.
  • Uso de PaginatedDataTable
    • Una alternativa más profesional, ideal para datasets grandes:
  • Incluye paginación por defecto
    • Ocupa menos memoria
    • Es más amigable para UX
  • Implementación con DataTableSource
    • Si necesitas un rendimiento superior, usa un modelo basado en DataTableSource, que permite:
  • Cargar solo las filas visibles
    • Conectar con APIs
    • Implementar lazy-loading
  • Performance tips
    • Desactiva funciones que no uses (sort, selection)
  • Evita widgets pesados dentro de DataCell
    • Usa const siempre que puedas

6. Ejemplos avanzados y casos reales

Una de las cosas que más me sorprendió cuando empecé a usar DataTable es lo flexible que puede ser:

  • Tablas con imágenes (avatars)
  • Celdas con botones de acción
  • Tablas conectadas a streams
  • Tablas con scroll horizontal + vertical
  • Tablas con filtros personalizados

En mi caso, una vez necesité mostrar una tabla con 10 columnas; la única forma viable fue envolverla en SingleChildScrollView horizontal y controlar el tamaño de cada columna manualmente.

⭐ 1. DataTable con scroll horizontal y vertical

Ideal cuando tienes muchas columnas y muchas filas.

SizedBox(
 height: 400,
 child: SingleChildScrollView(
   scrollDirection: Axis.vertical,
   child: SingleChildScrollView(
     scrollDirection: Axis.horizontal,
     child: DataTable(
       columns: const [
         DataColumn(label: Text("ID")),
         DataColumn(label: Text("Nombre")),
         DataColumn(label: Text("Correo")),
         DataColumn(label: Text("Rol")),
         DataColumn(label: Text("Estado")),
       ],
       rows: List.generate(20, (index) {
         return DataRow(
           cells: [
             DataCell(Text("$index")),
             DataCell(Text("Usuario $index")),
             DataCell(Text("user$index@mail.com")),
             DataCell(Text(index % 2 == 0 ? "Admin" : "User")),
             DataCell(Text(index % 2 == 0 ? "Activo" : "Inactivo")),
           ],
         );
       }),
     ),
   ),
 ),
)

⭐ 2. DataTable con acciones dentro de DataCell

Botones, íconos y acciones útiles.

DataTable(
 columns: const [
   DataColumn(label: Text("Producto")),
   DataColumn(label: Text("Precio")),
   DataColumn(label: Text("Acciones")),
 ],
 rows: [
   DataRow(cells: [
     DataCell(Text("Laptop")),
     DataCell(Text("\$1200")),
     DataCell(
       Row(
         children: [
           IconButton(
             icon: Icon(Icons.edit),
             onPressed: () {
               print("Editar");
             },
           ),
           IconButton(
             icon: Icon(Icons.delete, color: Colors.red),
             onPressed: () {
               print("Eliminar");
             },
           ),
         ],
       ),
     )
   ])
 ],
)

⭐ 3. DataTable editable (con diálogo)

Un flujo simple pero elegante.

void _editarCelda(BuildContext context, String valorInicial) async {
 TextEditingController controller = TextEditingController(text: valorInicial);
 await showDialog(
   context: context,
   builder: (_) => AlertDialog(
     title: Text("Editar valor"),
     content: TextField(
       controller: controller,
     ),
     actions: [
       TextButton(
         onPressed: () => Navigator.pop(context),
         child: Text("Cancelar"),
       ),
       ElevatedButton(
         onPressed: () {
           print("Nuevo valor: ${controller.text}");
           Navigator.pop(context);
         },
         child: Text("Guardar"),
       ),
     ],
   ),
 );
}
DataTable(
 columns: const [
   DataColumn(label: Text("Nombre")),
   DataColumn(label: Text("Edad")),
 ],
 rows: [
   DataRow(
     cells: [
       DataCell(
         Text("Andrés"),
         showEditIcon: true,
         onTap: () => _editarCelda(context, "Andrés"),
       ),
       DataCell(
         Text("28"),
         showEditIcon: true,
         onTap: () => _editarCelda(context, "28"),
       ),
     ],
   ),
 ],
)

⭐ 4. DataTable generada dinámicamente desde una lista

Super común cuando cargas datos desde API o base de datos.

final List<Map<String, dynamic>> usuarios = [
 {"nombre": "Luis", "edad": 21, "pais": "México"},
 {"nombre": "Laura", "edad": 32, "pais": "Perú"},
 {"nombre": "Akira", "edad": 29, "pais": "Japón"},
];
DataTable(
 columns: const [
   DataColumn(label: Text("Nombre")),
   DataColumn(label: Text("Edad")),
   DataColumn(label: Text("País")),
 ],
 rows: usuarios
     .map(
       (u) => DataRow(
         cells: [
           DataCell(Text(u["nombre"])),
           DataCell(Text(u["edad"].toString())),
           DataCell(Text(u["pais"])),
         ],
       ),
     )
     .toList(),
)

⭐ 5. PaginatedDataTable completo (ideal para muchas filas)

class UsuariosDataSource extends DataTableSource {
 final List<Map<String, dynamic>> usuarios;
 UsuariosDataSource(this.usuarios);
 @override
 DataRow? getRow(int index) {
   if (index >= usuarios.length) return null;
   final user = usuarios[index];
   return DataRow(
     cells: [
       DataCell(Text(user["id"].toString())),
       DataCell(Text(user["nombre"])),
       DataCell(Text(user["email"])),
     ],
   );
 }
 @override
 bool get isRowCountApproximate => false;
 @override
 int get rowCount => usuarios.length;
 @override
 int get selectedRowCount => 0;
}

Uso:

PaginatedDataTable(
 header: Text("Usuarios"),
 columns: const [
   DataColumn(label: Text("ID")),
   DataColumn(label: Text("Nombre")),
   DataColumn(label: Text("Email")),
 ],
 source: UsuariosDataSource([
   {"id": 1, "nombre": "Ana", "email": "ana@mail.com"},
   {"id": 2, "nombre": "Carlos", "email": "carlos@mail.com"},
   {"id": 3, "nombre": "Mina", "email": "mina@mail.com"},
 ]),
 rowsPerPage: 2,
)

⭐ 6. DataTable con formato personalizado (colores y estilos)

DataTable(
 headingRowColor: MaterialStateProperty.all(Colors.blueGrey),
 headingTextStyle: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
 dataRowColor: MaterialStateProperty.resolveWith<Color?>(
   (states) {
     if (states.contains(MaterialState.selected)) {
       return Colors.blue.withOpacity(0.2);
     }
     return null;
   },
 ),
 columns: const [
   DataColumn(label: Text("Tarea")),
   DataColumn(label: Text("Estado")),
 ],
 rows: [
   DataRow(
     selected: true,
     cells: [
       DataCell(Text("Revisar PR #32")),
       DataCell(Text("En progreso")),
     ],
   ),
   DataRow(cells: [
     DataCell(Text("Actualizar documentación")),
     DataCell(Text("Pendiente")),
   ]),
 ],
)

7. Conclusión

Crear una tabla en Flutter con DataTable es sencillo, pero dominarla requiere entender sus límites y cómo extenderla.

Personalmente, creo que es ideal para tablas pequeñas o medianas y para interfaces de administración. Pero cuando tu dataset crece, conviene migrar a 

PaginatedDataTable o soluciones basadas en DataTableSource.

Con las prácticas adecuadas, es un widget extremadamente útil y flexible.

❓ FAQs

  • ¿Cómo hago editable una DataTable en Flutter?
    • showEditIcon solo muestra el ícono. Debes manejar el onTap del DataCell y abrir un diálogo o formulario.
  • ¿DataTable sirve para listas grandes?
    • Hasta cierto punto. Más de 1000 filas puede ser lento. Para eso usa PaginatedDataTable o DataTableSource.
  • ¿Cuál es la diferencia entre DataTable y PaginatedDataTable?
    • DataTable muestra toda la data; PaginatedDataTable la divide en páginas y mejora el rendimiento.

Siguiente paso, aprende a usar el widget GestureDetector para implementar eventos click entre otros en cualquier widget en Flutter

Acepto recibir anuncios de interes sobre este Blog.

Los Datatable son ideales para mostrar grid de información a nuestro usuario, podemos indicar celdas editables, ordenación y más; por supuesto el contenido de la celda es un widget, por lo tanto podemos colocar lo que sea.

| 👤 Andrés Cruz

🇺🇸 In english