Provider封裝了InheritedWidget的功能,並讓我們能更容易地使用,而provider提供了我們:
在使用前先重新建構我們project,將components資料夾改成widgets並重新命名裡面的檔案
pubspec.yaml
dependencies:
provider: ^6.0.3
我們創建models和states資料夾,並先創建todo model
todo\lib\models\todo_model.dart
import 'dart:convert';
class TodoModel {
TodoModel({
required this.title,
required this.done,
required this.date,
});
final String title;
final bool done;
final String date;
factory TodoModel.fromJson(String str) => TodoModel.fromMap(json.decode(str));
String toJson() => json.encode(toMap());
factory TodoModel.fromMap(Map<String, dynamic> json) => TodoModel(
title: json["title"],
done: json["done"],
date: json["date"],
);
Map<String, dynamic> toMap() => {
"title": title,
"done": done,
"date": date,
};
}
創建我們的狀態管理
todo\lib\states\Itodo_state.dart
import 'package:todo/models/todo_model.dart';
abstract class ITodoState {
List<TodoModel> getTodos();
void addTodo(TodoModel todo);
}
todo\lib\states\todo_state.dart
import 'package:flutter/cupertino.dart';
import 'package:todo/models/todo_model.dart';
import 'package:todo/states/Itodo_state.dart';
class TodoState with ChangeNotifier implements ITodoState {
List<TodoModel> todos = [];
@override
List<TodoModel> getTodos() {
// TODO: implement getTodos
notifyListeners();
return todos;
}
@override
void addTodo(TodoModel todo) {
// TODO: implement addTodo
todos.add(todo);
notifyListeners();
}
}
我們在app入口加入我們的state
main.dart
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:todo/states/todo_state.dart';
import 'package:todo/ui/screens/nav_screen.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider.value(
value: TodoState(),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: NavScreen(),
debugShowCheckedModeBanner: false,
),
);
}
}
創建todo\lib\ui\widgets\todo_list_widget.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/src/foundation/key.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:provider/provider.dart';
import 'package:todo/states/todo_state.dart';
import 'package:todo/ui/widgets/todo_item_widget.dart';
class TodoList extends StatelessWidget {
const TodoList({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final _todoState = Provider.of<TodoState>(context);
return Column(
children: _todoState.todos
.map(
(e) => TodoItem(title: e.title, done: e.done),
)
.toList(),
);
}
}
接著修改
todo\lib\ui\widgets\todo_item_widget.dart
import 'dart:math';
import 'package:flutter/material.dart';
class TodoItem extends StatefulWidget {
final String title;
final bool done;
const TodoItem({
Key? key,
required this.title,
required this.done,
}) : super(key: key);
@override
State<TodoItem> createState() => _TodoItemState();
}
class _TodoItemState extends State<TodoItem> {
late Color color = Color(Random().nextInt(0xffffffff));
@override
Widget build(BuildContext context) {
return Container(
color: color,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const FlutterLogo(),
Text(widget.title),
TextButton(onPressed: () {}, child: Text('Done')),
ElevatedButton(onPressed: () {}, child: Text('Delete')),
],
),
);
}
}
以及將TodoList加入到我們的screen中
todo\lib\ui\screens\home_screen.dart
import 'package:flutter/material.dart';
import 'package:flutter/src/foundation/key.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:provider/provider.dart';
import 'package:todo/models/todo_model.dart';
import 'package:todo/states/todo_state.dart';
import 'package:todo/ui/widgets/todo_item_widget.dart';
import 'package:todo/ui/widgets/todo_list_widget.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final TrackingScrollController _trackingScrollController =
TrackingScrollController();
@override
Widget build(BuildContext context) {
final _todoState = Provider.of<TodoState>(context);
TodoModel testTodo = TodoModel(
title: "Just Test", done: false, date: DateTime.now().toString());
return CustomScrollView(
controller: _trackingScrollController,
slivers: [
SliverAppBar(
title: Text('Home Screen'),
),
SliverToBoxAdapter(
child: TodoList(),
),
SliverToBoxAdapter(
child: ElevatedButton(
child: Text('Add todo test'),
onPressed: () {
_todoState.addTodo(testTodo);
},
),
),
],
);
}
}
接著,我們來測試。我們能看到我們能跨組建的進行狀態管理了。
簡單來說,就是我們在根widget引入了Provider,而在其之下的子widgets裡的狀態改變後會往上傳回Provider,之後在往下面傳遞到我們的子widget中。
我們簡單的介紹如何使用Provider後,明天我們會使用我們主要使用的狀態管理Riverpod來進行我們Todo管理,我們明天見