Hola mundo!!
Introducción
Tanto si desarrolla una aplicación nativa como una híbrida, el manejo del estado es un problema que debemos enfrentar y tener bajo control. Para administrar el estado global de una aplicación enFlutter
existen varias maneras, en este post abordaremosProvider
, una biblioteca bastante popular que nos ayudará con este trabajo.
Aplicación de ejemplo
Para ver el funcionamiento deProvider
, vamos a realizar una sencilla aplicación que nos ejemplifique.
Esta app muestra una pantalla con unAppBar
y su título, en el centro unText
, y dos botones flotantes en la esquina inferior derecha, que tendrán como función cambiar el valor del texto que será mostrado tanto en el título delAppBar
como en elText
del body de la app.
Tenemos en cuenta que el valor del texto será administrado de manera global.
Dejo el link del ejercicio para quien desee descargarlo:
https://github.com/hextiandro/flutter_provider_pattern
Manos a la obra
Primeramente instalaremos la biblioteca:provider: ^5.0.0
(En el momento que escribí el post esta era la versión).
La podemos encontrar en:https://pub.dev/packages/provider
Dentro de lib creamos una carpeta llamada widgets y dentro un archivo llamado floating_actions.dart,lib/widgets/floating_actions.dart
para crear el widget con los dos botones flotantes:
import'package:flutter/material.dart';classFloatingActionextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){(context);returnColumn(mainAxisAlignment:MainAxisAlignment.end,children:<Widget>[FloatingActionButton(child:Icon(Icons.wifi),backgroundColor:Colors.orange,onPressed:(){}),SizedBox(height:10.0,),FloatingActionButton(child:Icon(Icons.bluetooth),backgroundColor:Colors.blue,onPressed:(){})],);}}
Notemos que elonPressed
lo tenemos sin acción, más adelante agregaremos su funcionalidad.
Ahora dentro delib/widgets
crearemos otro archivo llamado body,lib/widgets/body.dart
para crear elwidget
con el texto centralizado.
import'package:flutter/material.dart';classBodyextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){(context);returnCenter(child:Text("",style:TextStyle(fontSize:20),),);}}
El texto mostrado por ahora es la cadena vacía.
Crearemos otrowidget
dentro de lib, llamado homelib/Home.dart
:
import'package:flutter/material.dart';classHomeextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Center(child:Text("")),),body:Body(),floatingActionButton:FloatingAction(),);}}
Aquí estamos renderizando unScaffold
, con unAppBar
y su título vacío por el momento, además renderizamos loswidgets
Body
yFloatingAction
creados anteriormente.
Nada deProvider
aún, solo vamos armando la interfaz gráfica de la app, pasemos a modificar elmain.dart
.
Nuestro archivomain.dart
debería lucir así por el momento:
import'package:flutter/material.dart';import'package:provider_pattern/home.dart';voidmain()=>runApp(MyApp());classMyAppextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(title:'Provider',home:Home());}}
Con esto tenemos todo listo para comenzar a construir nuestroProvider
; hagamos lo siguiente:
Dentro de lib creamos otro directorio llamdo provider y dentro un archivo llamado signal_mode.dart,lib/provider/signal_mode.dart
import'package:flutter/material.dart';classSignalModeextendsChangeNotifier{String_signalMode='Wifi mode';StringgetsignalMode=>_signalMode;setsignalMode(Stringmode){this._signalMode=mode;notifyListeners();}}
Listo, este es nuestroProvider
, es la clase que se ocupa de centralizar el valor de la variable privada_signalMode
de tipoString
que es el texto que se mostrará tanto en el título delAppBar
como en el centro de la pantalla.
Notemos el primer detalle que extiende deChangeNotifier
clase encargada de exponer los eventos de notificación,
veamos que tenemos un métodoget
para obtener el valor de_signalMode
, y un métodoset
para modificarlo, dentro de este método vemos la llamada anotifyListeners()
que es quien va a notificar a todos loswidgets
que escuchen a este provider del cambio, para asi actualizar su estado.
Es momento de encapsular aquelloswidgets
que van a escuhar los cambios.
Como queremos tener el control del estado en todos los niveles de la aplicación lo haremos en elmain
.
Tenga en cuenta que no necesariamente se debe envolver en el nivel más alto de la aplicación en caso que desees compartir determinado estado para determinado nivel.
Si modificamos nuestromain
quedaría de la siguiente forma:
import'package:flutter/material.dart';import'package:provider/provider.dart';import'package:provider_pattern/home.dart';import'package:provider_pattern/provider/signal_mode.dart';voidmain()=>runApp(MyApp());classMyAppextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnChangeNotifierProvider(create:(_)=>SignalMode(),child:MaterialApp(title:'Provider',home:Home()),);}}
De esta manera toda la app está en condiciones de escuchar los cambios de la claseSignalMode
Desde ahora ya podemos integrar los distintoswidgets
de nuestra app. Modifiquemos la claseFloatingAction
para conectarla con nuestroProvider
quedando de la siguiente forma:
import'package:flutter/material.dart';import'package:provider/provider.dart';import'package:provider_pattern/provider/signal_mode.dart';classFloatingActionextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){finalsignal=Provider.of<SignalMode>(context);returnColumn(mainAxisAlignment:MainAxisAlignment.end,children:<Widget>[FloatingActionButton(child:Icon(Icons.wifi),backgroundColor:Colors.orange,onPressed:(){signal.signalMode="Wifi mode";}),SizedBox(height:10.0,),FloatingActionButton(child:Icon(Icons.bluetooth),backgroundColor:Colors.blue,onPressed:(){signal.signalMode="Bluetooth mode";})],);}}
Notemos aquí en la siguiente línea:
finalsignal=Provider.of<SignalMode>(context);
de esta manera obtenemos una instancia de nuestroProvider
especificando que es de tipoSignalMode
.
El otro punto a notar aquí es en elonPressed
de los botones, cada uno hace una llamada modificando el valor designalMode
onPressed:(){signal.signalMode="Wifi mode";})
onPressed:(){signal.signalMode="Bluetooth mode";})
De esta manera podemos modifcar el estado global, ahora solamente debemos mostrar los valores, veamos como:
import'package:flutter/material.dart';import'package:provider_pattern/provider/signal_mode.dart';import'package:provider_pattern/widgets/body.dart';import'package:provider_pattern/widgets/floating_actions.dart';import'package:provider/provider.dart';classHomeextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){finalsignal=Provider.of<SignalMode>(context);returnScaffold(appBar:AppBar(title:Center(child:Text(signal.signalMode)),),body:Body(),floatingActionButton:FloatingAction(),);}}
En la claseHome
igualmente obtenemos la instancia delProvider
y leemos la propiedadsignalHome
.
De la misma forma lo hacemos en la claseBody
:
import'package:flutter/material.dart';import'package:provider/provider.dart';import'package:provider_pattern/provider/signal_mode.dart';classBodyextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){finalsignal=Provider.of<SignalMode>(context);returnCenter(child:Text(signal.signalMode,style:TextStyle(fontSize:20),),);}}
Ya, es todo!!
Hemos finalizado nuestro ejemplo, pero les dejaré una última consideración para la utilización de múltiples providers tendríamos que modificar nuevamente nuestromain
de la siguiente forma:
voidmain()=>runApp(AppState());classAppStateextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnMultiProvider(providers:[ChangeNotifierProvider(create:(_)=>SignalMode())],child:MyApp(),);}}classMyAppextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(title:'Provider',home:Home());}}
Percatarse aquí comoMultiPorvider
admite un arreglo deProvider
:
providers:[ChangeNotifierProvider(create:(_)=>SignalMode())],
Conclusiones
Hasta aquí este post, espero haberme explicado bien y de alguna manera haberle sido útil, nos vemos en la próxima!!
Chao Mundo!!
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse