El proveedor es una técnica de administración de estado simple que se utiliza para administrar una parte de los datos en torno a la aplicación. Básicamente es un contenedor de widgets heredados, pero es fácil de entender y administrar.
Antes de continuar, debemos comprender algunos conceptos en el proveedor:
- ChangeNotifier : es básicamente una clase simple que se usa para notificar cualquier cambio que ocurra en un modelo dado a la parte de la aplicación que los está escuchando. Podemos describirlos como un servicio de suscripción. es decir, cualquier cambio en los datos se actualiza en todas las partes de la aplicación que están suscritas a ella.
- ChangeNotifierProvider : es un widget disponible en el paquete del proveedor que proporciona una instancia de ChangeNotifier a sus hijos. Básicamente se coloca por encima de todo el paquete que necesita los datos del modelo.
- Consumidor : podemos usar los datos del modelo a través de Consumer ya que ChangeNotfierProvider está presente como padre. Tenemos que especificar los genéricos (<TaskData> aquí) para que el proveedor sepa qué datos buscar. Tiene un generador de argumentos. Builder es una función que se llama cuando hay un cambio en los datos. Tiene tres contextos de argumentos, que es el contexto actual del constructor, luego la instancia de ChangeNotifier (datos aquí), y el tercero es un elemento secundario que se usa para widgets grandes con fines de optimización.
Syntax: return Consumer<TaskData>( builder: (context, data, child) { return Text(data.task); }, );
Configuración de la aplicación:
Ahora que hemos cubierto los conceptos básicos de Provider . Ahora entenderemos cada uno de estos temas con la ayuda de una aplicación de muestra. Construiremos una aplicación de gestión de tareas de muestra .
Primero, debemos agregar el paquete del proveedor a la sección de dependencias de pubspec.yaml.
dependencies: flutter: sdk: flutter provider: ^4.3.2+4 #ADD
Crearemos un directorio modelo dentro del directorio lib y agregaremos los archivos task.dart y task_data.dart dentro de él.
Dart
import 'package:flutter/foundation.dart'; class Task { String task; bool completed; Task({@required this.task, this.completed = false}); void toggle() { completed = !completed; } }
El archivo task.dart tiene una clase Task con dos campos.
- Tarea de string que almacena el nombre de la tarea que se mostrará en la aplicación cuando se agregue.
- bool completó, que alternará según la tarea, ya sea que se complete o no.
También hay una función de alternar que cambia las tareas de verdadero a falso y viceversa.
Dart
import 'dart:collection'; import 'package:flutter/foundation.dart'; import 'package:task_management/model/task.dart'; class TaskData with ChangeNotifier { List<Task> _tasks = []; UnmodifiableListView<Task> get tasks => UnmodifiableListView(_tasks); void addTask(Task task) { _tasks.add(task); notifyListeners(); } void toggleTask(Task task) { task.toggle(); notifyListeners(); } void removeTask(Task task) { _tasks.remove(task); notifyListeners(); } }
El archivo task_data.dart tiene la clase TaskData que se usa para administrar los datos. Definimos esta clase con ChangeNotifier para que los datos estén disponibles para las partes de la aplicación que los están escuchando. Los componentes de la clase son
- Lista de tareas (_tasks) que es un miembro privado para que los datos no se puedan cambiar desde fuera de la aplicación.
- Hay una versión no modificable de esa lista (tareas) para que los datos estén disponibles para su uso dentro de la aplicación.
- El método addTask se usa para agregar una nueva tarea a la aplicación.
- El toggleTask se usa para cambiar la tarea de completada a no completada y viceversa.
- También hay un removeTask para eliminar una tarea en particular de la lista de tareas.
- Hay una llamada a applyListeners() al final de cada método para que los oyentes de los datos reciban una notificación cuando los datos cambien.
Vamos a agregar ChangeNotifierProvider en main.dart sobre todos los widgets. Como nuestra aplicación es bastante simple con solo dos pantallas, debemos colocarla en main.dart para que esté disponible para sus descendientes. El main.dart es el siguiente:
Dart
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'model/task_data.dart'; import 'screens/home.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (context) => TaskData(), child: MaterialApp( debugShowCheckedModeBanner: false, title: 'Provider Demo', theme: ThemeData( primarySwatch: Colors.green, ), home: Home(), ), ); } }
El widget MaterialApp es hijo de ChangeNotifierProvider , que toma un campo de creación para obtener la instancia de TaskData . Creamos dos pantallas después de esto que se definen en el directorio de pantallas que se define en el directorio lib y dos archivos, es decir, home.dart y add_task.dart en él.
- La pantalla de Inicio se utiliza para mostrar el contenido de la Lista de tareas
- Agregar pantalla de tareas que se utiliza para agregar una nueva tarea a las listas de tareas.
Dart
import 'package:flutter/material.dart'; import 'package:task_management/task_list.dart'; import 'add_task.dart'; class Home extends StatelessWidget { // create the appbar @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('GeeksforGeeks'), ), body: Container( padding: EdgeInsets.all(20), child: TaskList(), ), floatingActionButton: FloatingActionButton( child: Icon( Icons.add, ), onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (context) => AddTask())); }, ), ); } }
La pantalla de inicio contiene una barra de aplicaciones y luego un contenedor que tiene widgets secundarios de lista de tareas que muestran la lista de tareas y un botón de acción flotante para agregar nuevas tareas a la aplicación.
Dart
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:task_management/model/task.dart'; import 'package:task_management/model/task_data.dart'; class AddTask extends StatelessWidget { @override Widget build(BuildContext context) { String text = ''; return Scaffold( appBar: AppBar( title: Text('Add Task'), ), body: Container( padding: EdgeInsets.all(18), child: Column( children: [ TextField( onChanged: (c) => text = c, decoration: InputDecoration( contentPadding: EdgeInsets.symmetric(horizontal: 10), hintText: 'Enter Task', border: const OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(8.0)), ), ), ), // add button RaisedButton( shape: RoundedRectangleBorder( borderRadius: BorderRadius.all( Radius.circular(8), ), ), child: Text( 'Submit', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 18, color: Colors.black), ), // assign action onPressed: () { Provider.of<TaskData>(context, listen: false) .addTask(Task(task: text)); Navigator.pop(context); }, ) ], ), ), ); } }
La pantalla AddTask nos permite agregar una nueva tarea con el interruptor predeterminado para estar apagado (es decir, la tarea no está completa). Aquí usamos Provider.of , con el parámetro de escucha establecido en demasiado falso para agregar los datos en la lista. No hemos utilizado Consumer aquí porque no necesitamos los datos.
Ahora vamos a crear el widget que representará las tareas en la pantalla. Así que definimos el siguiente widget TaskList en lib llamado task_list.dart como:
Dart
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:task_management/model/task_data.dart'; class TaskList extends StatelessWidget { @override Widget build(BuildContext context) { return Consumer<TaskData>(builder: (context, data, child) { return ListView.builder( scrollDirection: Axis.vertical, shrinkWrap: true, itemCount: data.size, itemBuilder: (context, index) { final task = data.tasks[index]; // gesture detection return GestureDetector( onLongPress: () => data.removeTask(task), child: Container( margin: EdgeInsets.only(bottom: 10), padding: EdgeInsets.fromLTRB(12, 5, 8, 5), width: double.infinity, decoration: BoxDecoration( color: Colors.black12, borderRadius: BorderRadius.circular(8)), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ // text field Text( task.task, style: TextStyle( decoration: task.completed ? TextDecoration.lineThrough : null, fontSize: 16, fontWeight: FontWeight.bold), ), // switch case Switch( value: task.completed, onChanged: (c) => data.toggleTask(task), ), ], ), ), ); }, ); }); } }
Producción:
Aquí hemos utilizado el Consumidor para obtener los datos de TaskList. También proporcionamos las funcionalidades para eliminar y alternar la tarea, manteniendo presionada para eliminar y alternar para marcar como completada.
Publicación traducida automáticamente
Artículo escrito por muazzamfaraaz y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA