大到整個app的狀態,用戶使用app是登陸狀態,仍是遊客狀態;小到一個按鈕的狀態,按鈕是點擊選中狀態仍是未點擊狀態等等,這些都是狀態管理。編程
Flutter 應用是 聲明式 的,這也就意味着 Flutter 構建的用戶界面就是應用的當前狀態。bash
一旦你的界面狀態發生改變,就會觸發界面的從新繪製,繪製出你想要的界面,而不是像iOS的OC語言那樣去獲取須要改變狀態的控件,而後修改它架構
Flutter中的狀態管理又分爲短時狀態和應用狀態。app
在下方你能夠看到一個底部導航欄中當前被選中的項目是如何被被保存在 _MyHomepageState 類的 _index 變量中。在這個例子中,_index 是一個短時狀態。less
class MyHomepage extends StatefulWidget {
@override
_MyHomepageState createState() => _MyHomepageState();
}
class _MyHomepageState extends State<MyHomepage> {
int _index = 0;
@override
Widget build(BuildContext context) {
return BottomNavigationBar(
currentIndex: _index,
onTap: (newIndex) {
setState(() {
_index = newIndex;
});
},
// ... items ...
);
}
}
複製代碼
在這裏,使用 setState() 和一個變量就能達到管理狀態的目的。你的 app 中的其餘部分不須要訪問 _index。這個變量只會在 MyHomepage widget 中改變。並且,若是用戶關閉並重啓這個 app,_index會被重置而不會繼續保持原來的狀態。ide
應用狀態,若是你想在你的應用中的多個部分之間共享一個非短時的狀態,而且在用戶會話期間保留這個狀態,咱們稱之爲應用狀態(有時也稱共享狀態)。 應用狀態的一些例子:函數
一、用戶選項
二、登陸信息
三、一個社交應用中的通知
四、一個電商應用中的購物車
五、一個新聞應用中的文章已讀/未讀狀態
複製代碼
在 Flutter 中,通常是將存儲狀態的對象置於 widget 樹中對應 widget 的上層,當它發生改變的時候,它對應的widget會從上層開始重構。由於這個機制,因此 widget 無需考慮生命週期的問題—它只須要針對 上層存儲數據的對象 聲明所需顯示內容便可。當內容發生改變的時候,舊的 widget 就會消失,徹底被新的 widget 替代。 Flutter原生提供了兩個方法來管理共享狀態:測試
class ADCounterWidget extends InheritedWidget {
// 1. 共享的數據
final int counter;
// 2. 定義構造方法
ADCounterWidget({this.counter, Widget child}): super(child: child);
// 3. 找到當前Widget樹中最近的InheritedWidget
static ADCounterWidget of(BuildContext context) {
// 沿着Element樹, 去找到最近的ADCounterElement, 從Element中取出Widget對象
return context.dependOnInheritedWidgetOfExactType();
}
// 4. 要不要回調State中的didChangeDependencies方法
@override
bool updateShouldNotify(ADCounterWidget oldWidget) {
return oldWidget.counter != counter;
}
}
複製代碼
class HYHomePage extends StatefulWidget {
@override
_HYHomePageState createState() => _HYHomePageState();
}
class _HYHomePageState extends State<HYHomePage> {
int data = 100;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("InheritedWidget"),
),
body: HYDataWidget(
counter: data,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
HYShowData()
],
),
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
setState(() {
data++;
});
},
),
);
}
}
複製代碼
建立HYDataWidget,而且傳入數據(這裏點擊按鈕會修改數據,而且出發從新build)優化
Provider庫有三個主要用到的類:ui
void main() {
runApp(ChangeNotifierProvider(
create: (context) => CounterProvider(),
child: MyApp(),
));
}
class CounterProvider extends ChangeNotifier {
int _counter = 100;
intget counter {
return _counter;
}
set counter(int value) {
_counter = value;
notifyListeners();
}
}
複製代碼
class HYHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("列表測試"),
),
body: Center(
child: Consumer<CounterProvider>(
builder: (ctx, counterPro, child) {
return Text("當前計數:${counterPro.counter}", style: TextStyle(fontSize: 20, color: Colors.red),);
}
),
),
floatingActionButton: Consumer<CounterProvider>(
builder: (ctx, counterPro, child) {
return FloatingActionButton(
child: child,
onPressed: () {
counterPro.counter += 1;
},
);
},
child: Icon(Icons.add),
),
);
}
}
複製代碼
Consumer的builder方法有三個參數:
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第二個頁面"),
),
floatingActionButton: Consumer<CounterProvider>(
builder: (ctx, counterPro, child) {
return FloatingActionButton(
child: child,
onPressed: () {
counterPro.counter += 1;
},
);
},
child: Icon(Icons.add),
),
);
}
}
複製代碼