前言一:接下來一段時間我會陸續更新一些列Flutter文字教程更新進度: 每週至少兩篇;html
更新地點: 首發於公衆號,次日更新於掘金、思否、開發者頭條等地方;前端
更多交流: 能夠添加個人微信 372623326,關注個人微博:coderwhyvue
但願你們能夠 幫忙轉發,點擊在看,給我更多的創做動力。算法
在開發中,某些Widget狀況下咱們展現的數據並非一層不變的:好比Flutter默認程序中的計數器案例,點擊了+號按鈕後,顯示的數字須要+1;編程
好比在開發中,咱們會進行下拉刷新、上拉加載更多,這時數據也會發生變化;api
而StatelessWidget一般用來展現哪些數據固定不變的,若是數據會發生改變,咱們使用StatefulWidget;瀏覽器
若是你有閱讀過默認咱們建立Flutter的示例程序,那麼你會發現它建立的是一個StatefulWidget。微信
爲何選擇StatefulWidget呢?網絡
變量
來記錄當前的狀態,再把這個變量顯示到某個Text Widget上;變量
發生改變時,咱們對應的Text上顯示的內容也要發生改變;可是有一個問題,我以前說過定義到Widget中的數據都是不可變的,必須定義爲final,爲何呢?數據結構
成員變量
必須是final
的;Flutter如何作到咱們在開發中定義到Widget中的數據必定是final的呢?
咱們來看一下Widget的源碼:
@immutable abstract class Widget extends DiagnosticableTree { // ...省略代碼 }
這裏有一個很關鍵的東西@immutable
註解
,這設計到Dart的元編程,咱們這裏不展開講;實際上官方有對@immutable進行說明:
結論: 定義到Widget中的數據必定是不可變的,須要使用final來修飾
既然Widget是不可變,那麼StatefulWidget如何來存儲可變的狀態呢?
Flutter將StatefulWidget設計成了兩個類:
建立一個StatefulWidget,咱們一般會按照以下格式來作:
State的實例
,而且它調用build方法去獲取StatefulWidget但願構建的Widget;class MyStatefulWidget extends StatefulWidget { @override State<StatefulWidget> createState() { // 將建立的State返回 return MyState(); } } class MyState extends State<MyStatefulWidget> { @override Widget build(BuildContext context) { return <構建本身的Widget>; } }
思考:爲何Flutter要這樣設計呢?
這是由於在Flutter中,只要數據改變了Widget就須要從新構建(rebuild)
咱們經過一個案例來練習一下StatefulWidget,仍是以前的計數器案例,可是咱們按照本身的方式進行一些改進。
案例效果以及佈局以下:
onPress屬性
是傳入一個回調函數
,當按鈕點擊時被回調;
下面咱們來看看代碼實現:
class MyCounterWidget extends StatefulWidget { @override State<StatefulWidget> createState() { // 將建立的State返回 return MyCounterState(); } } class MyCounterState extends State<MyCounterWidget> { int counter = 0; @override Widget build(BuildContext context) { return Center( child: Text("當前計數:$counter", style: TextStyle(fontSize: 30),), ); } }
class MyCounterState extends State<MyCounterWidget> { int counter = 0; @override Widget build(BuildContext context) { 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: () { }, ), RaisedButton( color: Colors.orangeAccent, child: Text("-1", style: TextStyle(fontSize: 18, color: Colors.white),), onPressed: () { }, ) ], ), Text("當前計數:$counter", style: TextStyle(fontSize: 30),) ], ), ); } }
咱們如今要監聽狀態的改變,當狀態改變時要修改counter變量
:
如何可讓Flutter知道咱們的狀態發生改變了,從新構建咱們的Widget呢?
onPressed: () { setState(() { counter++; }); },
這樣就能夠實現想要的效果了:
什麼是生命週期呢?
Flutter小部件的生命週期:
在這個版本中,我講解那些經常使用的方法和回調,下一個版本中我解釋一些比較複雜的方法和回調
那麼StatefulWidget有哪些生命週期的回調呢?它們分別在什麼狀況下執行呢?
咱們知道StatefulWidget自己由兩個類組成的:StatefulWidget
和State
,咱們分開進行分析
首先,執行StatefulWidget中相關的方法:
其次,調用createState建立State對象時,執行State類的相關方法:
二、執行initState,咱們一般會在這個方法中執行一些數據初始化的操做,或者也可能會發送網絡請求;
咱們來經過代碼進行演示:
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("執行了MyCounterWidget的構造方法"); } @override State<StatefulWidget> createState() { print("執行了MyCounterWidget的createState方法"); // 將建立的State返回 return MyCounterState(); } } class MyCounterState extends State<MyCounterWidget> { int counter = 0; MyCounterState() { print("執行MyCounterState的構造方法"); } @override void initState() { super.initState(); print("執行MyCounterState的init方法"); } @override void didChangeDependencies() { // TODO: implement didChangeDependencies super.didChangeDependencies(); print("執行MyCounterState的didChangeDependencies方法"); } @override Widget build(BuildContext context) { print("執行執行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("當前計數:$counter", style: TextStyle(fontSize: 30),) ], ), ); } @override void didUpdateWidget(MyCounterWidget oldWidget) { super.didUpdateWidget(oldWidget); print("執行MyCounterState的didUpdateWidget方法"); } @override void dispose() { super.dispose(); print("執行MyCounterState的dispose方法"); } }
打印結果以下:
flutter: HomeBody build flutter: 執行了MyCounterWidget的構造方法 flutter: 執行了MyCounterWidget的createState方法 flutter: 執行MyCounterState的構造方法 flutter: 執行MyCounterState的init方法 flutter: 執行MyCounterState的didChangeDependencies方法 flutter: 執行執行MyCounterState的build方法 // 注意:Flutter會build全部的組件兩次(查了GitHub、Stack Overflow,目前沒查到緣由) flutter: HomeBody build flutter: 執行了MyCounterWidget的構造方法 flutter: 執行MyCounterState的didUpdateWidget方法 flutter: 執行執行MyCounterState的build方法
當咱們改變狀態,手動執行setState方法後會打印以下結果:
flutter: 執行執行MyCounterState的build方法
咱們來學習幾個前面生命週期圖中提到的屬性,可是沒有詳細講解的
一、mounted是State內部設置的一個屬性,事實上咱們不瞭解它也能夠,可是若是你想深刻了解它,會對State的機制理解更加清晰;
二、dirty state的含義是髒的State
三、clean state的含義是乾淨的State
這個章節又講解一些理論的東西,可能並不會直接講授Flutter的知識,可是會對你之後寫任何的代碼,都具有一些簡單的知道思想;
編程範式對於初學編程的人來講是一個虛無縹緲的東西,可是倒是咱們平常開發中都在默認遵循的一些模式和方法;
好比咱們最爲熟悉的 面向對象編程
就是一種編程範式,與之對應或者結合開發的包括:面向過程編程、函數式編程、面向協議編程;
另外還有兩個對應的編程範式:命令式編程
和 聲明式編程
上面的描述仍是太籠統了,咱們來看一些具體點的例子;
下面的代碼沒有寫過前端的能夠簡單看一下
下面的代碼是在前端開發中我寫的兩個demo,做用都是點擊按鈕後修改h2標籤的內容:
從2009年開始(數據來自維基百科),聲明式編程就開始流行起來,而且目前在Vue、React、包括iOS中的SwiftUI中以及Flutter目前都採用了聲明式編程。
如今咱們來開發一個需求:顯示一個Hello World,以後又修改爲了Hello Flutter
若是是傳統的命令式編程,咱們開發Flutter的模式極可能是這樣的:(注意是想象中的僞代碼)
final text = new Text(); var title = "Hello World"; text.setContent(title); // 修改數據 title = "Hello Flutter"; text.setContent(title);
若是是聲明式編程,咱們一般會維護一套數據集:
var title = "Hello World"; Text(title); // 告訴Text內部顯示的是title // 數據改變 title = "Hello Flutter"; setState(() => null); // 通知從新build Widget便可
上面的代碼過於簡單,可能不能體現出Flutter聲明式編程的優點所在,可是在之後的開發中,咱們都是按照這種模式在進行開始,咱們一塊兒來慢慢體會;
備註:全部內容首發於公衆號,以後除了Flutter也會更新其餘技術文章,TypeScript、React、Node、uniapp、mpvue、數據結構與算法等等,也會更新一些本身的學習心得等,歡迎你們關注