下面我们介绍一种用 Provider 做应用状态管理的方法。需要先给项目安装一个包,打开 pubspec.yml ,在 dependencies 里面,添加一个 provider ,设置一下要使用的版本号,^3.1.0+1。 保存一下这个文件,编辑器会自动帮我们准备好这个新的依赖。
然后去创建一个东西,放在 lib/src,providers 里面,文件名字是 current_page.dart。 在这个文件里创建一个类。名字叫 CurrentPage。
这个类里的东西一会儿可以提供给需要的小部件,就是 IndexedStack 小部件,还有 BottomNavigationBar 小部件。
类里面添加一个 int 类型的属性,名字是 _index,默认让它等于 0 。然后再添加一个 getter 方法 int get 名字是 index ,返回的东西就是 _index 属性的值。
下面再添加一个 setter 方法, set index,方法接收一个 int 类型的参数,名字是 value ,方法里面,让 _index 的值等于方法接收的 value 参数的值。
让这个类有监听功能,可以再给它混合一个东西,with ChangeNotifier,要使用它可以导入 flutter 里的 foundation.dart 。
在这个 index setter 方法里面,现在我们可以用一下 notifyListeners 方法。 这样使用这个 setter 方法的时候,监听它的小部件就会被重建。
Provider
下面我们要把这个 CurrentPage 提供给需要它的小部件,需要它的是这个 IndexedStack 小部件,还有 AppBottomNavigationBar 小部件。
在这两个小部件的父辈那里可以提供它们需要的东西,比如在这个 Scaffold 小部件上面提供,command + . ,选择 Wrap with new Widget,可以再用一个 ChangeNotifierProvider 这个东西来自之前我们安装的 Provider。
然后把要提供的东西的类型交给它,这里就是 CurrentPage 。 除了 child 属性以外,需要再给 ChangeNotifierProvider 再提供一个 builder 属性。它的值就是要提供的东西,用一个方法返回,方法接收一个 context 参数,返回的是 CurrentPage 。
这样我们就可以在它下面所有的小部件里面获取到 CurrentPage 里的东西。
使用
比如先打开这个 AppBottomNavigationBar 小部件,得到 Provider 里提供的东西有几种方法,可以使用 Provider.of 方法,也可以使用 Consumer 小部件。
在 build 方法里,添加一个 currentPage,它的值用一下 Provider.of,把需要的 Provider 类型告诉 of 方法,这里就是 CurrentPage,方法有个 context 参数。
然后重新设置一下 BottomNavigationBar 小部件的 currentIndex 属性的值,把它换成 currentPage.index。
在定义 CurrentPage 这个类的时候,里面添加了一个 getter 方法,名字就是 index,访问它的时候,返回的就是它里面的 _index 的值,默认就是数字 0 。
再修改一下 onTap 属性的值,可以直接给它一个方法,方法接收 value 参数,方法里面可以设置一下 currentPage.index 的值,让它等于 value。
定义 CurrentPage 的时候,里面添加了一个 setter 方法,名字是 index,方法做的事情是设置一下 _index 的值。然后通知所有的监听者,值有变化了,这样这些监听者就会重建。
之前在这个小部件里添加的属性还有方法用不到了,可以删除掉,这样这个小部件就不需要是一个 StatefulWidget ,它也可以是一个 StatelessWidget。把这个小部件改造成一个 StatelessWidget。
打开调试,刷新一下, 如果应用退出,可以重新再运行一下。
再回到 App,在它里面的这个 IndexedStack 小部件里面,也需要用一下 CurrentPage,这里获取到提供的这个 CurrentPage ,可以用一下 Consumer ,选中 IndexedStack ,command + . 选择 Wrap with new Widget ,用一下 Consumer, 把要获取到的东西的类型交给它,这里就是 CurrentPage。
这个 Consumer 里面需要提供一个 builder 属性,它的值是个方法,方法可以返回一个小部件,方法有三个参数,context,还有获取到的值, 比如 currentPage,第三个参数是 child 。
然后把 IndexedStack 小部件的 index 属性的值换成 currentPage 里的 index 。
预览
到模拟器上预览一下,按一下底部导航栏上的导航项目,现在就可以切换显示对应的页面。