En aquest tema, explorarem dues maneres fonamentals de gestionar l'estat en Flutter: setState
i InheritedWidget
. Aquests conceptes són crucials per crear aplicacions reactives i eficients.
Què és l'Estat en Flutter?
L'estat és qualsevol dada que pot canviar durant el cicle de vida d'un widget. Per exemple, el text d'un camp de text, la posició d'un botó o la selecció d'un element en una llista.
setState
setState
és una manera senzilla i directa de gestionar l'estat en Flutter. S'utilitza principalment en widgets stateful (StatefulWidget
). Quan es crida a setState
, Flutter sap que ha de reconstruir el widget amb el nou estat.
Exemple de setState
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text('Exemple de setState')), body: Center(child: CounterWidget()), ), ); } } class CounterWidget extends StatefulWidget { @override _CounterWidgetState createState() => _CounterWidgetState(); } class _CounterWidgetState extends State<CounterWidget> { int _counter = 0; void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('Has premut el botó aquesta quantitat de vegades:'), Text( '$_counter', style: Theme.of(context).textTheme.headline4, ), ElevatedButton( onPressed: _incrementCounter, child: Text('Incrementa'), ), ], ); } }
Explicació del Codi
- Creació del
StatefulWidget
:CounterWidget
és un widget amb estat. - Definició de l'Estat:
_CounterWidgetState
és la classe que manté l'estat del widget. - Inicialització de l'Estat:
_counter
és la variable d'estat que es modifica. - Actualització de l'Estat:
_incrementCounter
crida asetState
per actualitzar_counter
i redibuixar el widget.
InheritedWidget
InheritedWidget
és una manera més avançada de gestionar l'estat, especialment quan l'estat ha de ser compartit entre múltiples widgets. Permet que els widgets descendents accedeixin a l'estat sense necessitat de passar-lo explícitament a través del constructor.
Exemple de InheritedWidget
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text('Exemple de InheritedWidget')), body: CounterProvider( child: CounterWidget(), ), ), ); } } class CounterProvider extends InheritedWidget { final int counter; final Function() incrementCounter; CounterProvider({Key? key, required Widget child}) : counter = 0, incrementCounter = () {}, super(key: key, child: child); @override bool updateShouldNotify(CounterProvider oldWidget) { return oldWidget.counter != counter; } static CounterProvider? of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType<CounterProvider>(); } } class CounterWidget extends StatelessWidget { @override Widget build(BuildContext context) { final provider = CounterProvider.of(context); return Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('Has premut el botó aquesta quantitat de vegades:'), Text( '${provider?.counter}', style: Theme.of(context).textTheme.headline4, ), ElevatedButton( onPressed: provider?.incrementCounter, child: Text('Incrementa'), ), ], ); } }
Explicació del Codi
- Creació del
InheritedWidget
:CounterProvider
és unInheritedWidget
que conté l'estat i una funció per incrementar-lo. - Mètode
of
: Permet als widgets descendents accedir a l'estat delCounterProvider
. - Ús del
InheritedWidget
:CounterWidget
accedeix a l'estat a través del mètodeof
.
Comparació entre setState
i InheritedWidget
Característica | setState |
InheritedWidget |
---|---|---|
Facilitat d'ús | Fàcil | Més complex |
Escalabilitat | Limitada a widgets individuals | Ideal per a compartir estat |
Rendiment | Pot ser menys eficient en grans apps | Més eficient per a estat compartit |
Casos d'ús | Estat local | Estat global o compartit |
Exercici Pràctic
Exercici
Crea una aplicació Flutter que utilitzi InheritedWidget
per gestionar l'estat d'un comptador que es pot incrementar des de diferents pantalles.
Solució
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: CounterProvider( child: HomeScreen(), ), ); } } class CounterProvider extends StatefulWidget { final Widget child; CounterProvider({required this.child}); @override _CounterProviderState createState() => _CounterProviderState(); static _CounterProviderState? of(BuildContext context) { return context.findAncestorStateOfType<_CounterProviderState>(); } } class _CounterProviderState extends State<CounterProvider> { int _counter = 0; void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { return _InheritedCounter( counter: _counter, incrementCounter: _incrementCounter, child: widget.child, ); } } class _InheritedCounter extends InheritedWidget { final int counter; final Function() incrementCounter; _InheritedCounter({ required this.counter, required this.incrementCounter, required Widget child, }) : super(child: child); @override bool updateShouldNotify(_InheritedCounter oldWidget) { return oldWidget.counter != counter; } } class HomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { final provider = CounterProvider.of(context); return Scaffold( appBar: AppBar(title: Text('Home Screen')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('Has premut el botó aquesta quantitat de vegades:'), Text( '${provider?._counter}', style: Theme.of(context).textTheme.headline4, ), ElevatedButton( onPressed: provider?._incrementCounter, child: Text('Incrementa'), ), ElevatedButton( onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (context) => SecondScreen()), ); }, child: Text('Anar a la Segona Pantalla'), ), ], ), ), ); } } class SecondScreen extends StatelessWidget { @override Widget build(BuildContext context) { final provider = CounterProvider.of(context); return Scaffold( appBar: AppBar(title: Text('Second Screen')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('Has premut el botó aquesta quantitat de vegades:'), Text( '${provider?._counter}', style: Theme.of(context).textTheme.headline4, ), ElevatedButton( onPressed: provider?._incrementCounter, child: Text('Incrementa'), ), ], ), ), ); } }
Explicació de la Solució
CounterProvider
: UnStatefulWidget
que conté l'estat del comptador i una funció per incrementar-lo._InheritedCounter
: UnInheritedWidget
que proporciona l'estat i la funció d'increment a tots els widgets descendents.HomeScreen
iSecondScreen
: Dues pantalles que accedeixen i modifiquen l'estat del comptador a través delCounterProvider
.
Conclusió
En aquest tema, hem après a gestionar l'estat en Flutter utilitzant setState
i InheritedWidget
. Hem vist exemples pràctics de com utilitzar cada mètode i hem comparat les seves característiques. Amb aquests coneixements, estàs preparat per gestionar l'estat de manera eficient en les teves aplicacions Flutter.
Curs de Desenvolupament Flutter
Mòdul 1: Introducció a Flutter
- Què és Flutter?
- Configuració de l'Entorn de Desenvolupament
- Comprensió de l'Arquitectura de Flutter
- Creació de la Teva Primera Aplicació Flutter
Mòdul 2: Conceptes Bàsics de Programació en Dart
- Introducció a Dart
- Variables i Tipus de Dades
- Sentències de Flux de Control
- Funcions i Mètodes
- Programació Orientada a Objectes en Dart
Mòdul 3: Widgets de Flutter
- Introducció als Widgets
- Widgets Stateless vs Stateful
- Widgets Bàsics
- Widgets de Disseny
- Widgets d'Entrada i Formulari
Mòdul 4: Gestió de l'Estat
Mòdul 5: Navegació i Enrutament
- Introducció a la Navegació
- Navegació Bàsica
- Rutes Nomenades
- Passar Dades Entre Pantalles
- Deep Linking
Mòdul 6: Xarxes i APIs
- Obtenir Dades d'Internet
- Analitzar Dades JSON
- Gestió d'Errors de Xarxa
- Ús d'APIs REST
- Integració de GraphQL
Mòdul 7: Persistència i Emmagatzematge
- Introducció a la Persistència
- Preferències Compartides
- Emmagatzematge de Fitxers
- Base de Dades SQLite
- Ús de Hive per a l'Emmagatzematge Local
Mòdul 8: Conceptes Avançats de Flutter
- Animacions en Flutter
- Pintura Personalitzada i Canvas
- Canals de Plataforma
- Isolates i Concurrència
- Optimització del Rendiment
Mòdul 9: Proves i Depuració
- Introducció a les Proves
- Proves Unitàries
- Proves de Widgets
- Proves d'Integració
- Tècniques de Depuració
Mòdul 10: Desplegament i Manteniment
- Preparació per al Llançament
- Construcció per a iOS
- Construcció per a Android
- Integració i Desplegament Continu (CI/CD)
- Manteniment i Actualització de la Teva Aplicació