📜  Flutter – 使用嵌套模型和提供者

📅  最后修改于: 2021-09-02 05:49:20             🧑  作者: Mango

提供程序是一种简单的状态管理技术,用于管理应用程序周围的一段数据。它基本上是继承小部件的包装器,但易于理解和管理。

在继续之前,我们必须了解 provider 中的一些概念——

  • ChangeNotifier :它基本上是一个简单的类,用于将给定模型发生的任何更改通知给正在侦听它们的应用程序部分。我们可以将它们描述为订阅服务。即对数据的任何更改都会更新到订阅它的应用程序的所有部分。
  • ChangeNotifierProvider :它是提供程序包中可用的小部件,它为其子项提供ChangeNotifier的实例。它基本上放在所有需要模型数据的包之上。
  • Consumer :我们可以通过 Consumer 使用模型的数据,因为ChangeNotfierProvider作为它的父级存在。我们必须指定泛型(此处为 ),以便提供者知道要获取哪些数据。它有一个参数生成器。 Builder 是一个在数据发生变化时调用的函数。它有三个参数上下文,即构建器的当前上下文,然后是 ChangeNotifier 的实例(此处为数据),第三个是用于大型小部件以进行优化的子项。
Syntax:
return Consumer(
  builder: (context, data, child) {
    return Text(data.task);
  },
);

设置应用程序:

现在我们已经介绍了Provider的基本概念。现在我们将在示例应用程序的帮助下理解这些主题中的每一个。我们将构建一个示例任务管理应用程序

首先,我们需要将提供程序包添加到pubspec.yaml的依赖项部分

dependencies:
  flutter:
    sdk: flutter
  provider: ^4.3.2+4 #ADD

我们将在 lib 目录中创建一个模型目录并添加任务。 dart和 task_data。 dart文件在里面。

Dart
import 'package:flutter/foundation.dart';
  
class Task {
  String task;
  bool completed;
  Task({@required this.task, this.completed = false});
  void toggle() {
    completed = !completed;
  }
}


Dart
import 'dart:collection';
import 'package:flutter/foundation.dart';
import 'package:task_management/model/task.dart';
  
class TaskData with ChangeNotifier {
  List _tasks = [];
  UnmodifiableListView 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();
  }
}


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(),
      ),
    );
  }
}


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()));
        },
      ),
    );
  }
}


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(context, listen: false)
                    .addTask(Task(task: text));
                Navigator.pop(context);
              },
            )
          ],
        ),
      ),
    );
  }
}


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(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),
                  ),
                ],
              ),
            ),
          );
        },
      );
    });
  }
}


任务。 dart文件有一个包含两个字段的类Task

  1. 字符串任务,用于存储添加时要在应用程序上显示的任务的名称。
  2. bool completed 它将根据任务完成与否进行切换。

还有一个切换函数,可以将任务从真切换为假,反之亦然。

Dart

import 'dart:collection';
import 'package:flutter/foundation.dart';
import 'package:task_management/model/task.dart';
  
class TaskData with ChangeNotifier {
  List _tasks = [];
  UnmodifiableListView 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();
  }
}

任务数据。 dart文件具有用于管理数据的TaskData类。我们使用ChangeNotifier定义这个类,以使数据可用于正在侦听它的应用程序部分。类的组成部分是

  • 任务列表 (_tasks) 是私有成员,因此无法从应用程序外部更改数据。
  • 该列表(任务)有一个不可修改的版本,以便数据可在应用程序内使用。
  • addTask方法用于向应用程序添加新任务。
  • toggleTask用于将任务从已完成更改为未完成,反之亦然。
  • 还有一个removeTask用于从任务列表中删除特定任务。
  • 每个方法的末尾都有一个 notifyListeners() 调用,以便在数据更改时通知数据的侦听器。

我们将在main 中添加ChangeNotifierProvider 。dart高于所有小部件。由于我们的应用程序非常简单,只有两个屏幕,因此我们必须将其放置在屏幕中。 dart以便它的后代可以使用它。主要的。dart如下-

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(),
      ),
    );
  }
}

MaterialApp小部件是ChangeNotifierProvider子代,它采用create字段来获取TaskData的实例。我们在此之后创建两个屏幕,它们定义在 lib 目录中定义的屏幕目录和两个文件即home.conf 中。dart和 add_task。dart它。

  • 主屏幕用于显示任务列表的内容
  • 添加任务屏幕,用于将新任务添加到任务列表。

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()));
        },
      ),
    );
  }
}

主屏幕包含一个应用程序栏,然后容器,有子任务列表控件,显示任务列表,以及FloatingActionButton新任务添加到应用程序。

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(context, listen: false)
                    .addTask(Task(task: text));
                Navigator.pop(context);
              },
            )
          ],
        ),
      ),
    );
  }
}

AddTask 屏幕让我们添加一个默认开关关闭的新任务(即任务未完成)。这里我们使用Provider.of ,其listen参数设置为 false 无法将数据添加到列表中。我们这里没有使用 Consumer,因为我们不需要数据。

现在我们将制作将在屏幕上呈现任务的小部件。所以我们在 lib 中定义了以下小部件TaskList ,名为 task_list。dart为:

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(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),
                  ),
                ],
              ),
            ),
          );
        },
      );
    });
  }
}

输出:

在这里,我们使用 Consumer 来获取 TaskList 的数据,我们还提供了删除和切换任务的功能,如长按删除和切换标记为完成。

想要一个更快节奏和更具竞争力的环境来学习 Android 的基础知识吗?
单击此处前往由我们的专家精心策划的指南,旨在让您立即做好行业准备!