前文
本文所提供的的狀態管理的方法爲provide以及provider這兩種,後續如果我使用了redux或state的話,就再來給大家分享
Flutter狀態持久化
目的
:
在我們日常開發中,每次點擊tab頁面後,都會出現從新加載當前頁面內容的現象,這種體驗給用戶看來很不友好,所以我們這裏就需要用到了Flutter狀態持久化。
兩種狀態持久化的方法
- IndexedStack控件
- AutomaticKeepAliveClientMixin
IndexedStack
原理:將所有的頁面都放到IndexStack當中,通過控制index屬性,來顯示哪個頁面(前端的小夥伴可以利用z-index來理解)
弊端:每一次加載APP的時候,都要將所有的頁面加載出來,才能達到頁面保持狀態的效果
原理圖:
如何使用?
在你的bottomNavigationBar頁面中,我們的body本來是控制顯示首頁的,現在我們用IndexedStack替換一下,下圖中的pageList是我的頁面數組
AutomaticKeepAliveClientMixin
結合tab切換保持頁面狀態相比IndexedStack而言配置起來稍微有些複雜,是結合BottomNavigationBar保持頁面狀態的時候進行配置的
原理:還沒搞懂。。。。。
如何使用?
- 首先實例化pageController,將BottomNavigationBar的 currentIndex值傳給pageController
- 在body入口 用PageView包裹住,設置好controller參數爲實例化的值,children則爲頁面數組
這裏說明一下,如果用PageView包裹住的話,tab頁切換就會有滑動切換的效果,所以這裏我們要設置一下onPageChanged方法,這樣底部標籤欄就可以跟隨切換而高亮了,下圖中由於疏忽忘記寫了,特附贈這段代碼
body: PageView(
controller: this._pageController,
children: this.pageList,
onPageChanged: (index){
setState(() {
this._currentIndex = index;
});
},
),
- 切換頁面的時候,通過BottomNavigationBar的onTap方法跳轉頁面,調用jumpToPage(index) 傳入index值 跳轉
- 子類都要通過with關鍵字混合繼承AutomaticKeepAliveClientMixin;
同時重寫wantKeepAlive方法,返回true
OK,到此爲止了, 狀態化管理目前就這兩種,大多數使用的是第二種,推薦第二種!
Flutter狀態管理之Provide
flutter_provide是Google項目下的狀態管理,推薦使用這個插件
關於Flutter的狀態管理,我是用前端的Vuex
去理解的,是將UI層和邏輯層分開的操作。
如何使用?
首先你要做的是在pubspec.yaml
引入provide
插件。
provide: ^1.0.2 #狀態管理
安裝完畢後,我們就可以使用了,首先要寫個狀態管理類,也就是邏輯層的類
,我創建的文件名爲test.dart
test.dart
import 'package:flutter/material.dart';
// 將頁面的業務邏輯 分到當前dart文件中
// ChangeNotifier 不限制類的獲取,誰都可以獲取當前類
class Counter with ChangeNotifier {
int currentIndex = 0;
int index = 0;
changeIndex(index){
currentIndex = index;
// 可以通知聽衆。局部刷新Widget
notifyListeners();
}
increment(){
index++;
notifyListeners();
}
}
創建好類之後,我們就將該狀態管理引入到我們的main.dart
入口文件當中,同時記得要引入provide插件
import 'package:provide/provide.dart'; // 狀態管理
import 'package:project/provide/test.dart';
引入進來後,我們來將該類以及provide實例化,這裏需要注意的是,實例化的時候是Providers(),並不是Provider(),最後在runApp()當中將provider註冊進去
void main() {
var counter = Counter();
var providers = Providers();
// 如果想添加新的狀態管理,在下面通過..添加就行
providers..provide(Provider<Counter>.value(counter))
runApp(ProviderNode(child:MyApp(), providers:providers));
}
好了,現在我們準備工作已經完事了,接下來我們來看看如何使用吧
import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import 'package:project/provide/BottomNavigation.dart';
class MessagePage extends StatefulWidget {
@override
_MessagePageState createState() => _MessagePageState();
}
class _MessagePageState extends State<MessagePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// Text('消息')
ShowText(),
Button()
],
),
)
);
}
}
class ShowText extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Provide<Counter>(
// counter 是自定義邏輯類
builder: (context, child, counter){
return Text(
'${counter.index}',
style: Theme.of(context).textTheme.display1,
);
},
)
);
}
}
class Button extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
child: Text('增加'),
onPressed: (){
// 調用改變狀態方法
Provide.value<Counter>(context).increment();
},
);
}
}
代碼分析:
在我們需要保持狀態管理的地方,利用Provider控件包裹起來,在調用builder方法 將控件返回出來,裏面有三個參數,第一個是上下文,第二個是子類,第三個是狀態管理類,我們通過第三個參數就可以訪問到我們的屬性值了,改變的方法也是通過value方法來調用管理類定義好的方法,這裏的value記得聲明泛型來指明我們的狀態管理類。
Flutter狀態管理之Provider
provider
是也是在谷歌項目下的狀態管理,作用和provide
都是一樣的,用於管理全局的數據狀態
如何使用?
首先你要做的是在pubspec.yaml
引入provider
插件。
provider: ^3.2.0
創建自定義狀態管理類Count.dart
import 'package:flutter/material.dart';
class Counter with ChangeNotifier{
int _count; // 狀態
// 實例化時就初始化數據
Counter(){
this._count = 0;
}
int get count=>_count; // 獲取當前狀態(爲什麼已經有個變量了,還要再寫一個變量賦值拋出去呢: 保護變量,避免狀態管理類被污染)
incCount(){
this._count++;
notifyListeners(); // 通知更新狀態
}
}
在main.dart
中使用MultiProvider控件包裹住所有內容,同時設置屬性providers
進行監聽狀態管理
import 'package:flutter/material.dart';
import 'package:test_03/router/routes.dart'; // 自定義路由
import 'package:provider/provider.dart'; // 狀態管理
import 'package:test_03/provider/Count.dart'; // 自定義狀態管理
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_)=>Counter()), // 監聽自定義的類
],
child: MaterialApp(
initialRoute: '/',
routes: routers,
onGenerateRoute: onGenerateRoute,
),
);
}
}
接下來就是在各個類中使用了,由於已經在main.js中用控件包裹住一層了,所以不需要像provide
一樣,還需要再次嵌套控件了,只需要在您需要使用的類中引入您的provider
插件以及自定義的狀態管理類
就可以了。
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_03/provider/Count.dart';
class Home extends StatefulWidget {
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
String data = "init";
@override
Widget build(BuildContext context) {
// <Counter> 是泛型指定自定義狀態類
var counterProvider = Provider.of<Counter>(context);
return Scaffold(
body: ListView(
children: <Widget>[
Text(data),
Text('${counterProvider.count}'),
RaisedButton(
child: Text('點擊修改狀態管理中的數據'),
onPressed: (){
counterProvider.incCount();
},
),
],
),
}
}
同理如果別的頁面也需要這個狀態數據,就像這樣引入就可以共用了
provider和provide的區別
不同之處
1、作者
provide
:Flutter早期沒有自己的狀態管理類,由Google的一名開發人員開發寫出的一款插件
provider
:Flutter官方團隊提供的官方插件
2、使用
provide
:
(1)需要在main.dart
中的void main(){ }主函數方法中進行初始化和註冊。
(2)各個dart類使用的時候需要在外層再次包裹一層Provide的控件
provider
:
(1)只需在main.js中的主控件外部包裹一層MultiProvider
控件,把providers
聲明好屬性就可以在內部使用了。
相同之處
在自定義狀態管理類時,都是混合使用的flutter內部提供的ChangeNotifier類,在通知時都是使用的notifyListeners()方法
OK! 徹底完結,有問題@我哦,告辭┏(^0^)┛