第一個(gè)Flutter項(xiàng)目--計(jì)數(shù)器示例

創(chuàng)建的flutter項(xiàng)目中,看一下這些部分是怎么組織起來的

在這個(gè)示例中峡懈,主要Dart代碼是在 lib/main.dart 文件中,下面我們看看該示例的源碼:

import 'package:flutter/material.dart';

// 應(yīng)用入口
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // 藍(lán)色主題 
        primarySwatch: Colors.blue,
      ),
      // 應(yīng)用首頁路由
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  
  final String title;
  
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

分析

1、導(dǎo)入包

import 'package:flutter/material.dart';

此行代碼作用是導(dǎo)入了Material UI組件庫躬它。Material是一種標(biāo)準(zhǔn)的移動(dòng)端和web端的視覺設(shè)計(jì)語言, Flutter默認(rèn)提供了一套豐富的Material風(fēng)格的UI組件东涡。

2冯吓、應(yīng)用入口

void main() => runApp(new MyApp());
  • 與C/C++、Java類似疮跑,F(xiàn)lutter 應(yīng)用中main函數(shù)為應(yīng)用程序的入口组贺,main函數(shù)中調(diào)用了,runApp 方法祖娘,它的功能是啟動(dòng)Flutter應(yīng)用失尖,它接受一個(gè)Widget參數(shù),在本示例中它是MyApp類的一個(gè)實(shí)例,該參數(shù)代表Flutter應(yīng)用掀潮。
  • main函數(shù)使用了(=>)符號(hào)菇夸,這是Dart中單行函數(shù)或方法的簡寫。

3胧辽、應(yīng)用結(jié)構(gòu)

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      //應(yīng)用名稱  
      title: 'Flutter Demo', 
      theme: new ThemeData(
        //藍(lán)色主題  
        primarySwatch: Colors.blue,
      ),
      //應(yīng)用首頁路由  
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
  • MyApp類代表Flutter應(yīng)用峻仇,它繼承了 StatelessWidget類,這也就意味著應(yīng)用本身也是一個(gè)widget邑商。
  • 在Flutter中摄咆,大多數(shù)東西都是widget,包括對(duì)齊(alignment)人断、填充(padding)和布局(layout)吭从。
  • Flutter在構(gòu)建頁面時(shí),會(huì)調(diào)用組件的build方法恶迈,widget的主要工作是提供一個(gè)build()方法來描述如何構(gòu)建UI界面(通常是通過組合涩金、拼裝其它基礎(chǔ)widget)。
  • MaterialApp 是Material庫中提供的Flutter APP框架暇仲,通過它可以設(shè)置應(yīng)用的名稱步做、主題、語言奈附、首頁及路由列表等全度。MaterialApp也是一個(gè)widget。
  • Scaffold 是Material庫中提供的頁面腳手架斥滤,它包含導(dǎo)航欄和Body以及FloatingActionButton(如果需要的話)将鸵。
  • home 為Flutter應(yīng)用的首頁,它也是一個(gè)widget佑颇。

4顶掉、首頁

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
 ...
}

MyHomePage 是應(yīng)用的首頁,它繼承自StatefulWidget類挑胸,表示它是一個(gè)有狀態(tài)的widget(Stateful widget)⊙魍玻現(xiàn)在,我們可以簡單認(rèn)為Stateful widget 和Stateless widget有兩點(diǎn)不同:

  • Stateful widget可以擁有狀態(tài)茬贵,這些狀態(tài)在widget生命周期中是可以變的凸克,而Stateless widget是不可變的。
  • Stateful widget至少由兩個(gè)類組成:
    • 一個(gè)StatefulWidget類闷沥。
    • 一個(gè) State類; StatefulWidget類本身是不變的咐容,但是 State類中持有的狀態(tài)在widget生命周期中可能會(huì)發(fā)生變化舆逃。

_MyHomePageState類是MyHomePage類對(duì)應(yīng)的狀態(tài)類。看到這里路狮,細(xì)心的讀者可能已經(jīng)發(fā)現(xiàn)虫啥,和MyApp 類不同, MyHomePage類中并沒有build方法奄妨,取而代之的是涂籽,build方法被挪到了_MyHomePageState方法中,至于為什么這么做砸抛,先留個(gè)疑問评雌,在分析完完整代碼后再來解答。

接下來直焙,我們看看_MyHomePageState中都包含哪些東西:

(1)狀態(tài)景东。

int _counter = 0;

_counter 為保存屏幕右下角帶“?”號(hào)按鈕點(diǎn)擊次數(shù)的狀態(tài)。

(2)設(shè)置狀態(tài)的自增函數(shù)奔誓。

void _incrementCounter() {
  setState(() {
     _counter++;
  });
}

當(dāng)按鈕點(diǎn)擊時(shí)斤吐,會(huì)調(diào)用此函數(shù),該函數(shù)的作用是先自增_counter厨喂,然后調(diào)用setState 方法和措。setState方法的作用是通知Flutter框架,有狀態(tài)發(fā)生了改變蜕煌,F(xiàn)lutter框架收到通知后派阱,會(huì)執(zhí)行build方法來根據(jù)新的狀態(tài)重新構(gòu)建界面, Flutter 對(duì)此方法做了優(yōu)化幌绍,使重新執(zhí)行變的很快颁褂,所以你可以重新構(gòu)建任何需要更新的東西,而無需分別去修改各個(gè)widget傀广。

(3)構(gòu)建UI界面

構(gòu)建UI界面的邏輯在build方法中颁独,當(dāng)MyHomePage第一次創(chuàng)建時(shí),_MyHomePageState類會(huì)被創(chuàng)建伪冰,當(dāng)初始化完成后誓酒,F(xiàn)lutter框架會(huì)調(diào)用Widget的build方法來構(gòu)建widget樹,最終將widget樹渲染到設(shè)備屏幕上贮聂。所以靠柑,我們看看_MyHomePageState的build方法中都干了什么事:

Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Text(
              'You have pushed the button this many times:',
            ),
            new Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: new FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: new Icon(Icons.add),
      ),
    );
  }
  • Scaffold 是 Material庫中提供的一個(gè)widget, 它提供了默認(rèn)的導(dǎo)航欄、標(biāo)題和包含主屏幕widget樹的body屬性吓懈。widget樹可以很復(fù)雜歼冰。
  • body的widget樹中包含了一個(gè)Center widget,Center 可以將其子widget樹對(duì)其到屏幕中心耻警, Center 子widget是一個(gè)Column widget隔嫡,Column的作用是將其所有子widget沿屏幕垂直方向依次排列甸怕, 此例中Column包含兩個(gè) Text子widget,第一個(gè)Text widget顯示固定文本 “You have pushed the button this many times:”腮恩,第二個(gè)Text widget顯示_counter狀態(tài)的數(shù)值梢杭。
  • floatingActionButton是頁面右下角的帶“?”的懸浮按鈕,它的onPressed屬性接受一個(gè)回調(diào)函數(shù)秸滴,代表它本點(diǎn)擊后的處理器武契,本例中直接將_incrementCounter作為其處理函數(shù)。

現(xiàn)在荡含,我們將整個(gè)流程串起來:當(dāng)右下角的floatingActionButton按鈕被點(diǎn)擊之后咒唆,會(huì)調(diào)用_incrementCounter,在_incrementCounter中内颗,首先會(huì)自增_counter計(jì)數(shù)器(狀態(tài))钧排,然后setState會(huì)通知Flutter框架狀態(tài)發(fā)生變化,接著均澳,F(xiàn)lutter會(huì)調(diào)用build方法以新的狀態(tài)重新構(gòu)建UI恨溜,最終顯示在設(shè)備屏幕上。

為什么要將build方法放在State中找前,而不是放在StatefulWidget中糟袁?

這主要是為了開發(fā)的靈活性。如果將build()方法在StatefulWidget中則會(huì)有兩個(gè)問題:

  • 狀態(tài)訪問不便

試想一下躺盛,如果我們的Stateful widget 有很多狀態(tài)项戴,而每次狀態(tài)改變都要調(diào)用build方法,由于狀態(tài)是保存在State中的槽惫,如果將build方法放在StatefulWidget中周叮,那么構(gòu)建時(shí)讀取狀態(tài)將會(huì)很不方便,如果真的將build方法放在StatefulWidget中的話界斜,由于構(gòu)建用戶界面過程需要依賴State仿耽,所以build方法將必須加一個(gè)State參數(shù),大概是下面這樣:

Widget build(BuildContext context, State state){
      //state.counter
      ...
}

這樣的話就只能將State的所有狀態(tài)聲明為公開的狀態(tài)各薇,這樣才能在State類外部訪問狀態(tài)项贺,但將狀態(tài)設(shè)置為公開后,狀態(tài)將不再具有私密性峭判,這樣依賴开缎,對(duì)狀態(tài)的修改將會(huì)變的不可控。將build()方法放在State中的話林螃,構(gòu)建過程則可以直接訪問狀態(tài)奕删,這樣會(huì)很方便。

  • 繼承StatefulWidget不便

例如疗认,F(xiàn)lutter中有一個(gè)動(dòng)畫widget的基類AnimatedWidget完残,它繼承自StatefulWidget類砌滞。AnimatedWidget中引入了一個(gè)抽象方法build(BuildContext context),繼承自AnimatedWidget的動(dòng)畫widget都要實(shí)現(xiàn)這個(gè)build方法』倒郑現(xiàn)在設(shè)想一下,如果StatefulWidget 類中已經(jīng)有了一個(gè)build方法绊茧,正如上面所述铝宵,此時(shí)build方法需要接收一個(gè)state對(duì)象,這就意味著AnimatedWidget必須將自己的State對(duì)象(記為_animatedWidgetState)提供給其子類华畏,因?yàn)樽宇愋枰谄鋌uild方法中調(diào)用父類的build方法鹏秋,代碼可能如下:

class MyAnimationWidget extends AnimatedWidget{
    @override
    Widget build(BuildContext context, State state){
      //由于子類要用到AnimatedWidget的狀態(tài)對(duì)象_animatedWidgetState,
      //所以AnimatedWidget必須通過某種方式將其狀態(tài)對(duì)象_animatedWidgetState
      //暴露給其子類   
      super.build(context, _animatedWidgetState)
    }
}

這樣很顯然是不合理的亡笑,因?yàn)?/p>

  • AnimatedWidget的狀態(tài)對(duì)象是AnimatedWidget內(nèi)部實(shí)現(xiàn)細(xì)節(jié)侣夷,不應(yīng)該暴露給外部。
  • 如果要將父類狀態(tài)暴露給子類仑乌,那么必須得有一種傳遞機(jī)制百拓,而做這一套傳遞機(jī)制是無意義的,因?yàn)楦缸宇愔g狀態(tài)的傳遞和子類本身邏輯是無關(guān)的晰甚。

綜上所述衙传,可以發(fā)現(xiàn),對(duì)于StatefulWidget厕九,將build方法放在State中蓖捶,可以給開發(fā)帶來很大的靈活性。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末扁远,一起剝皮案震驚了整個(gè)濱河市俊鱼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌畅买,老刑警劉巖并闲,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異皮获,居然都是意外死亡焙蚓,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門洒宝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來购公,“玉大人,你說我怎么就攤上這事雁歌『旰疲” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵靠瞎,是天一觀的道長比庄。 經(jīng)常有香客問我求妹,道長,這世上最難降的妖魔是什么佳窑? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任制恍,我火速辦了婚禮,結(jié)果婚禮上神凑,老公的妹妹穿的比我還像新娘净神。我一直安慰自己,他們只是感情好溉委,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布鹃唯。 她就那樣靜靜地躺著,像睡著了一般瓣喊。 火紅的嫁衣襯著肌膚如雪坡慌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天藻三,我揣著相機(jī)與錄音洪橘,去河邊找鬼。 笑死趴酣,一個(gè)胖子當(dāng)著我的面吹牛梨树,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播岖寞,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼抡四,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了仗谆?” 一聲冷哼從身側(cè)響起指巡,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎隶垮,沒想到半個(gè)月后藻雪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡狸吞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年勉耀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蹋偏。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡便斥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出威始,到底是詐尸還是另有隱情枢纠,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布黎棠,位于F島的核電站晋渺,受9級(jí)特大地震影響镰绎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜木西,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一畴栖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧八千,春花似錦驶臊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽扛门。三九已至鸠信,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間论寨,已是汗流浹背星立。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留葬凳,地道東北人绰垂。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像火焰,于是被迫代替她去往敵國和親劲装。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容