En Flutter, moitos widgets personalizados (como botóns, iconas ou contedores táctiles) precisan executar unha acción cando o usuario realiza unha interacción, por exemplo, ao premer unha tecla ou tocar un botón.
Para conseguilo, o widget non executa directamente a acción, senón que recibe unha función (callback) definida polo widget pai.
Deste modo, o widget pai decide que facer, e o fillo simplemente chama á función cando corresponde.
⚠️ Nota Importante: O obxectivo é crear widgets reutilizables e personalizables que poidamos empregar en distintas partes da aplicación. Para conseguilo, a miúdo necesitamos que o widget reciba unha función por parámetro, e isto é precisamente o que logramos empregando callbacks.
🧠 Que é exactamente un callback?
Un callback é unha función que se lle pasa como parámetro a outro widget para que a execute nun momento determinado (xeralmente cando ocorre un xesto).
Por exemplo, imaxina que temos unha función no widget pai:
void borrar() {
print("Borrando datos...");
}
E a pasamos a un botón:
ElevatedButton(
onPressed: borrar, // 👈 PASAMOS a función como callback (sen parénteses)
child: const Text("Borrar"),
);
Aquí:
borraré o callback.ElevatedButtonnon sabe que significa “borrar”; só sabe que, cando o usuario preme, debe chamar á función que lle chegou enonPressed.
Internamente, o botón fará algo así:
class MeuBoton extends StatelessWidget {
final VoidCallback onPressed;
const MeuBoton({super.key, required this.onPressed});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPressed, // 👈 chama ao callback cando se toca o botón
child: const Text("Son un botón"),
);
}
}
Deste xeito, o comportamento do botón é totalmente configurable: depende da función (callback) que lle pase o widget pai.
⚙️ Como se declara un callback nun widget personalizado?
Cando creas un widget, podes permitir que acepte unha función como parámetro.
As formas máis habituais son:
final VoidCallback onTap; // función sen parámetros e sen retorno
final void Function(int) onNumero; // función con parámetro
💡 Tipos de callbacks máis usados
| Tipo de callback | Cando usalo | Función no pai | Pai: como PASA o callback | Fillo: como RECIBE e USA |
|---|---|---|---|---|
Sen parámetrosVoidCallback | O fillo só debe avisar dunha acción | void borrar() { ... } | BotonBorrar(onTap: borrar) | onPressed: onTap |
Con númerovoid Function(int) | O fillo debe enviar un número | void sumar(int n) { ... } | TeclaNumero(onNumero: sumar) | onPressed: () => onNumero(7) |
Con textovoid Function(String) | O fillo debe enviar texto | void actualizar(String t) { ... } | CampoTexto(onCambio: actualizar) | onChanged: (v) => onCambio(v) |
Con obxectovoid Function(Persoa) | O fillo envía un obxecto completo | void gardarPersoa(Persoa p) { ... } | Editor(onGardar: gardarPersoa) | onPressed: () => onGardar(p) |
Callback que devolve valorint Function() / String Function() | O fillo necesita pedirlle información ao pai | int obterId() { ... } | Vista(onGetId: obterId) | final id = onGetId() |
Notas:
- Se non precisas datos, usa
VoidCallback.- Se precisas pasar un valor, usa
void Function(Tipo)(por exemplo,void Function(int)).
Equivalentes (sen parámetros):
final VoidCallback accion1;
final void Function() accion2; // fan o mesmo
⚡ Callback sen parámetros: VoidCallback
O tipo VoidCallback é a forma máis sinxela de definir un callback en Flutter.
Representa unha función sen argumentos e sen retorno, que se executa cando ocorre unha acción.
É moi común en botóns e xestos, como ElevatedButton, IconButton ou GestureDetector.
🧠 Exemplo práctico
class BotonSimple extends StatelessWidget {
final String texto;
final VoidCallback onTap;
const BotonSimple({super.key, required this.texto, required this.onTap});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onTap, // chamamos ao callback
child: Text(texto),
);
}
}
Uso:
BotonSimple(
texto: 'Borrar',
onTap: () {
print("Botón premido");
},
);
O fillo non sabe que debe facer → só chama onTap().
🧩 Callback con parámetros
Hai casos nos que non chega con saber que se premeu, senón que valor se premeu.
Por exemplo, nun teclado de calculadora, queremos saber que número tocou o usuario.
Para iso non abonda con VoidCallback (que non admite parámetros).
Debemos usar unha función que reciba un argumento, como:
final void Function(int) onNumero;
O fillo pode facer:
onTap(numeroBoton);
🔼 Comunicación fillo → pai mediante callbacks
Este patrón é fundamental:
o pai controla o estado, pero o fillo provoca cambios chamando á función que lle pasa o pai.
1️⃣ O widget pai define unha función e pásalla ao fillo
class _PantallaPrincipalState extends State<PantallaPrincipal> {
String nome = "Diego";
void actualizarNome(String novoNome) {
setState(() {
nome = novoNome;
});
}
@override
Widget build(BuildContext context) {
return EditorNomeCallback(
nomeInicial: nome,
aoGardar: actualizarNome, // 👈 callback enviado
);
}
}
2️⃣ O widget fillo recibe a función e chámase cando corresponda
class EditorNomeCallback extends StatefulWidget {
final String nomeInicial;
final Function(String) aoGardar;
const EditorNomeCallback({
super.key,
required this.nomeInicial,
required this.aoGardar,
});
@override
State<EditorNomeCallback> createState() => _EditorNomeCallbackState();
}
class _EditorNomeCallbackState extends State<EditorNomeCallback> {
late String nomeEditado;
@override
void initState() {
super.initState();
nomeEditado = widget.nomeInicial;
}
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
widget.aoGardar(nomeEditado); // 👈 comunicación cara arriba
Navigator.pop(context);
},
child: const Text("Gardar"),
);
}
}
📘 O exemplo completo:

📌 Paso de parámetros vs callbacks. Cando usar cada método?
| Método | Cando se recomenda |
|---|---|
| Navigator + pop(valor) | Cando o fillo é unha pantalla completa que debe devolver datos ao pai |
| Callback | Cando o fillo é parte da UI e hai comunicación continua e inmediata |
🧭 Resumo final
- O estado vive no pai.
- O fillo non modifica o estado directamente.
- O fillo chama unha función que lle pasa o pai.
- O pai actualiza o estado con
setState(). - Isto permite widgets totalmente reutilizables, simples e limpos.
🧪 Exemplo avanzado: dous tipos de callbacks
Neste exemplo móstrase como varios widgets fillos poden comunicarse cara arriba co widget pai para modificar o seu estado. Esta comunicación faise mediante callbacks, é dicir, funcións que o pai lles pasa aos fillos para que estes poidan executalas cando sexa necesario.

- 🧩 O estado vive en
PantallaPrincipal. Esta clase é unStatefulWidgetporque garda e actualiza o contador. Dispón de dúas funcións que modifican o estado mediantesetState(), e que se pasan aos fillos como callbacks:incrementarContador()→ suma 1sumarNumero(int numero)→ suma o valor indicado
- 🧩 Widgets fillos: reciben unha función e a executan. Hai dous tipos:
Contador_ExemploCallback: É unStatelessWidgetque recibe o contador e unha función sen parámetros. Ao premer o botón, chama ao callback e o pai actualiza o seu estado.BotonNumero_ExemploCallback: Tamén éStatelessWidget. Recibe un texto, un número e unha función con parámetro. Ao premer, chama ao callback pasando o número correspondente, e o pai actualiza o contador.