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:
_incrementCountercrida asetStateper actualitzar_counteri 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 unInheritedWidgetque conté l'estat i una funció per incrementar-lo. - Mètode
of: Permet als widgets descendents accedir a l'estat delCounterProvider. - Ús del
InheritedWidget:CounterWidgetaccedeix 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: UnStatefulWidgetque conté l'estat del comptador i una funció per incrementar-lo._InheritedCounter: UnInheritedWidgetque proporciona l'estat i la funció d'increment a tots els widgets descendents.HomeScreeniSecondScreen: 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ó
