# Optimización de Rendering en Flutter
Lograr 60 (o 120) FPS estables requiere entender qué es costoso y cómo evitarlo. Aquí tienes las mejores prácticas para optimizar el renderizado.
## 1. Minimizar Reconstrucciones (build)
El método `build()` debe ser rápido y puro.
### Usa `const` Constructors
Si un widget es constante, Flutter sabe que no necesita reconstruirlo nunca, incluso si su padre se reconstruye.
```dart
// ✅ Bueno
child: const Text('Título Fijo');
// ❌ Malo (se crea una nueva instancia cada vez)
child: Text('Título Fijo');
```
### Extraer Widgets
Divide widgets grandes en widgets pequeños.
- Si tienes un `setState` en un widget gigante, todo se reconstruye.
- Si extraes la parte que cambia a su propio widget, solo esa parte se reconstruye.
### `Consumer` / `BlocBuilder` Granulares
No envuelvas toda tu pantalla en un `BlocBuilder`. Envuélvelo solo en el widget específico que necesita los datos.
## 2. Optimización de Listas (ListView)
### Usa `ListView.builder`
Nunca uses `ListView(children: ...)` para listas largas. Eso construye todos los hijos de inmediato (aunque no se vean). `ListView.builder` los construye bajo demanda (lazy).
### `itemExtent` o `prototypeItem`
Si tus items tienen altura fija, díselo al ListView. Esto evita que Flutter tenga que calcular la altura de cada item para saber el tamaño total del scroll.
```dart
ListView.builder(
itemExtent: 50.0, // ✅ Optimización masiva
itemBuilder: ...
)
```
## 3. Evitar "Jank" en Animaciones
### No uses `Opacity` para animaciones
Cambiar la opacidad de un widget complejo puede ser costoso porque requiere buffers intermedios.
- **Mejor:** Usa `AnimatedOpacity` (optimizado).
- **Aún mejor:** Si solo quieres ocultarlo, usa `Visibility`.
### Usa `RepaintBoundary`
Si tienes una animación pequeña (ej. un spinner) dentro de una página estática compleja, envuelve la animación en `RepaintBoundary`.
Esto le dice a Flutter: "Pinta esto en una capa separada". Así, cuando el spinner gira, no se repinta toda la página, solo la capa del spinner.
```dart
RepaintBoundary(
child: CircularProgressIndicator(),
)
```
## 4. Imágenes
- **Cache:** Usa `cached_network_image`.
- **Tamaño:** No cargues una imagen de 4000x4000px para mostrarla en un icono de 50x50px. Usa `cacheWidth` / `cacheHeight` al cargarla para decodificarla a menor resolución.
```dart
Image.network(
url,
cacheWidth: 100, // Decodifica a este tamaño en memoria
)
```
## 5. Operaciones Costosas
- **Clip:** `ClipRRect`, `ClipPath` son costosos (usan anti-aliasing). Úsalos con moderación. `borderRadius` de un Container es más barato que `ClipRRect`.
- **Sombras:** `BoxShadow` es costoso.
- **SaveLayer:** Algunas operaciones (como opacidad con grupos o ciertos blend modes) llaman a `saveLayer` en el canvas, que es muy lento (crea una textura off-screen). Chequea el Performance Overlay para ver si abusas de esto.
## Resumen de Optimización
1. **Mide primero:** No optimices a ciegas. Usa DevTools.
2. **Const:** Pon `const` en todo lo que puedas.
3. **Lazy:** Usa builders para listas.
4. **Aísla:** Usa `RepaintBoundary` para separar lo que se mueve de lo estático.
5. **Simplifica:** Menos clips, sombras y opacidades innecesarias.
Este apartado profundiza en los conceptos clave, proporcionando ejemplos prácticos y mejores prácticas para su aplicación en proyectos reales.
Al comprender estos detalles, podrás diseñar soluciones más robustas, mantenibles y escalables en tus aplicaciones Flutter y Dart.