1. StatelessWidget
1.1 StatelessWidget通常是一些沒(méi)有狀態(tài)(State,也可以理解成data)需要維護(hù)的Widget:
- 它們的數(shù)據(jù)通常是直接寫死;
- 從parent widget中傳入的而且一旦傳入就不可以修改;
- 從InheritedWidget獲取來(lái)使用的數(shù)據(jù);
1.2 StatelessWidget包含一個(gè)必須重寫的方法:build方法;
StatelessWidget沒(méi)辦法主動(dòng)去執(zhí)行build方法,當(dāng)我們使用的數(shù)據(jù)發(fā)生改變時(shí),build方法會(huì)被重新執(zhí)行
build方法什么情況下被執(zhí)行呢?:
- 1)當(dāng)我們的StatelessWidget第一次被插入到Widget樹(shù)中時(shí)(也就是第一次被創(chuàng)建時(shí));
- 2)當(dāng)我們的父Widget(parent widget)發(fā)生改變時(shí),子Widget會(huì)被重新構(gòu)建;
- 3)如果我們的Widget依賴InheritedWidget的一些數(shù)據(jù),InheritedWidget數(shù)據(jù)發(fā)生改變時(shí);
2.有狀態(tài)的StatefulWidget
2.1 Flutter如何做到我們?cè)陂_(kāi)發(fā)中定義到Widget中的數(shù)據(jù)一定是final的呢?
@immutable
abstract class Widget extends DiagnosticableTree {
const Widget({ this.key });
...省略代碼...
}
這里有一個(gè)很關(guān)鍵的東西@immutable
- 我們似乎在Dart中沒(méi)有見(jiàn)過(guò)這種語(yǔ)法,這實(shí)際上是一個(gè) 注解,這涉及到Dart的元編程;
官方有對(duì)@immutable進(jìn)行說(shuō)明: - 來(lái)源: https://api.flutter.dev/flutter/meta/immutable-constant.html
- 說(shuō)明: 被@immutable注解標(biāo)明的類或者子類都必須是不可變的
結(jié)論: 定義到Widget中的數(shù)據(jù)一定是不可變的,需要使用final來(lái)修飾
2.2 如何存儲(chǔ)Widget狀態(tài)?
1)既然Widget是不可變,那么StatefulWidget如何來(lái)存儲(chǔ)可變的狀態(tài)呢?
- StatelessWidget無(wú)所謂,因?yàn)樗锩娴臄?shù)據(jù)通常是直接定義完后就不修改的。
- 但StatefulWidget需要有狀態(tài)(可以理解成變量)的改變,這如何做到呢?
2)Flutter將StatefulWidget設(shè)計(jì)成了兩個(gè)類:
- 也就是你創(chuàng)建StatefulWidget時(shí)必須創(chuàng)建兩個(gè)類:
- 一個(gè)類繼承自StatefulWidget,作為Widget樹(shù)的一部分;
- 一個(gè)類繼承自State,用于記錄StatefulWidget會(huì)變化的狀態(tài),并且根據(jù)狀態(tài)的變化,構(gòu)建出新的Widget;
3)創(chuàng)建一個(gè)StatefulWidget,我們通常會(huì)按照如下格式來(lái)做:
- 當(dāng)Flutter在構(gòu)建Widget Tree時(shí),會(huì)獲取State的實(shí)例,并且它調(diào)用build方法去獲取StatefulWidget希望構(gòu)建的Widget;
- 那么,我們就可以將需要保存的狀態(tài)保存在MyState中,因?yàn)樗强勺兊模?/li>
class MyStatefulWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// 將創(chuàng)建的State返回
return MyState();
}
}
class MyState extends State<MyStatefulWidget> {
@override
Widget build(BuildContext context) {
return <構(gòu)建自己的Widget>;
}
}
2.3 思考:為什么Flutter要這樣設(shè)計(jì)呢?
這是因?yàn)樵贔lutter中,只要數(shù)據(jù)改變了Widget就需要重新構(gòu)建(rebuild)
2.4 StatefulWidget生命周期
1)Flutter小部件的生命周期:
- StatelessWidget可以由父Widget直接傳入值,調(diào)用build方法來(lái)構(gòu)建,整個(gè)過(guò)程非常簡(jiǎn)單;
- 而StatefulWidget需要通過(guò)State來(lái)管理其數(shù)據(jù),并且還要監(jiān)控狀態(tài)的改變決定是否重新build整個(gè)Widget;
- 所以,我們主要討論StatefulWidget的生命周期,也就是它從創(chuàng)建到銷毀的整個(gè)過(guò)程;
2)那么StatefulWidget有哪些生命周期的回調(diào)呢?它們分別在什么情況下執(zhí)行呢?
- 在下圖中,灰色部分的內(nèi)容是Flutter內(nèi)部操作的,我們并不需要手動(dòng)去設(shè)置它們;
-
白色部分表示我們可以去監(jiān)聽(tīng)到或者可以手動(dòng)調(diào)用的方法;
image.png
import 'package:flutter/material.dart';
main(List<String> args) {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("HelloWorld"),
),
body: HomeBody(),
),
);
}
}
class HomeBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("HomeBody build");
return MyCounterWidget();
}
}
class MyCounterWidget extends StatefulWidget {
MyCounterWidget() {
print("執(zhí)行了MyCounterWidget的構(gòu)造方法");
}
@override
State<StatefulWidget> createState() {
print("執(zhí)行了MyCounterWidget的createState方法");
// 將創(chuàng)建的State返回
return MyCounterState();
}
}
class MyCounterState extends State<MyCounterWidget> {
int counter = 0;
MyCounterState() {
print("執(zhí)行MyCounterState的構(gòu)造方法");
}
@override
void initState() {
super.initState();
print("執(zhí)行MyCounterState的init方法");
}
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
print("執(zhí)行MyCounterState的didChangeDependencies方法");
}
@override
Widget build(BuildContext context) {
print("執(zhí)行執(zhí)行MyCounterState的build方法");
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
color: Colors.redAccent,
child: Text("+1", style: TextStyle(fontSize: 18, color: Colors.white),),
onPressed: () {
setState(() {
counter++;
});
},
),
RaisedButton(
color: Colors.orangeAccent,
child: Text("-1", style: TextStyle(fontSize: 18, color: Colors.white),),
onPressed: () {
setState(() {
counter--;
});
},
)
],
),
Text("當(dāng)前計(jì)數(shù):$counter", style: TextStyle(fontSize: 30),)
],
),
);
}
@override
void didUpdateWidget(MyCounterWidget oldWidget) {
super.didUpdateWidget(oldWidget);
print("執(zhí)行MyCounterState的didUpdateWidget方法");
}
@override
void dispose() {
super.dispose();
print("執(zhí)行MyCounterState的dispose方法");
}
}
打印結(jié)果如下:
flutter: HomeBody build
flutter: 執(zhí)行了MyCounterWidget的構(gòu)造方法
flutter: 執(zhí)行了MyCounterWidget的createState方法
flutter: 執(zhí)行MyCounterState的構(gòu)造方法
flutter: 執(zhí)行MyCounterState的init方法
flutter: 執(zhí)行MyCounterState的didChangeDependencies方法
flutter: 執(zhí)行執(zhí)行MyCounterState的build方法
// 注意:Flutter會(huì)build所有的組件兩次(查了GitHub、Stack Overflow,目前沒(méi)查到原因)
flutter: HomeBody build
flutter: 執(zhí)行了MyCounterWidget的構(gòu)造方法
flutter: 執(zhí)行MyCounterState的didUpdateWidget方法
flutter: 執(zhí)行執(zhí)行MyCounterState的build方法
當(dāng)我們改變狀態(tài),手動(dòng)執(zhí)行setState方法后會(huì)
flutter: 執(zhí)行執(zhí)行MyCounterState的build方法
學(xué)習(xí)內(nèi)容來(lái)自Flutter從入門到實(shí)戰(zhàn)
