今天預計和大家一起看看:
好的,那我們就開始吧!
main.dart
中的code如何構成模擬器上的畫面:最上方我們看到 main()
functionmain()
是dart裡面最高層級的function,一個dart應用程式只能使用一次,作為整個dart app啟動的入口。
我們可以看到這個main裡面執行的是runApp
。runApp
是flutter框架提供的method,啟動我們提供的Widget並運行在畫面上。
這邊我們傳入的組件是使用MyApp
class的constructor 建構的新的instance:MyApp()
接著我們就看到main()
裡面使用的MyApp
class的定義:MyApp
繼承了StatelessWidget
(無狀態組件,於下一章說明)本身和其所繼承的所有實踐,並且覆寫了build
方法。
在Widget中,build
method用於組建UI元件,交由flutter偵測UI結構後產生結構樹渲染於頁面上。
Flutter提供兩種App的設計風格指南:Material Design(Android App)為主的MaterialApp
,和Human Interface Guideline(iOS APP)為主的CupertinoApp
(Cupertino是Apple總部所在的城市)。我們可以依照需求決定要採用哪種設計風格。
這裏MyApp
的build()
回傳了一個新的MaterialApp
並且提供了參數:
MyHomePage
是一個StatefulWidget
(有狀態組件,同樣於下一章說明),包括MyHomePage
和_MyHomePageState
兩個部分:
MyHomePage class定義了建構一個實例所需的參數:title
,指定required this.title
代表建構時,title
為必需輸入的值,而輸入的參數會被存在實例中的title
field之中。
而MyHomePage
繼承的StatefuleWidget
有定義createState
method,用於產生狀態管理實例,MyHomePage
的狀態管理組件就是 private class _MyHomePageState
。
在_MyHomePageState
中紀錄了
_counter
儲存計數,_incrementCounter
來增加計數值。build
之中終於看到了本篇的主角:Scaffold
作為整個頁面的主要結構。在這裡的Scaffold
有三個主要的部分:
appBar
:主標題橫幅,body
:頁面主體,floatingActionButton
:右下角的按鍵我們也可以看到_incrementCounter
被塞在 FloatingActionButton
的onPress
之中、整個FloatinActionButton
也包著一個+號的Icon :Icon(Icons.add)
,這也解釋了頁面上點擊"+"之後會增加頁面上計數的行為。
由上面的敘述,可以看出啟動APP之後我們看到的其實是MyHomePage
堆疊各種組件所產生畫面。
Flutter強調一個重點概念:
Everything is a Widget
所有的頁面都是由一個一個的Widget(組件)構成,就跟樂高一樣,只要有恰當的積木,就可以組成任何的樣子。
值得一提的是,連「置中」、「對齊」、「外觀樣式」這類的排版概念,在Flutter裡面也是Widget:你可以建構一個自訂Widget A,再把Widget A用置中組件Center
包起來
Center(
children: const A();
)
這樣A組件就可以置中了,是不是非常神奇?
而Scaffold
的本意是支架,也就是它扮演了一個頁面支架的角色。要建構一個Scaffold Widget
可以依照需求輸入各種參數,比如說_MyAppState
用了appBar
, body
, floatingActionButton
來構成頁面主體
下面列舉一些scaffold常用的區塊:
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: '首頁',
tooltip: '',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: '設定',
tooltip: '',
),
],
),
drawer: Drawer(
child: ListView(
children: const <Widget>[
ListTile(
leading: Icon(Icons.access_alarm),
title: Text('Alarm'),
),
],
),
),
定義上滑式選單
bottomSheet: BottomSheet(
builder: (context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: const <Widget>[
ListTile(
leading: Icon(Icons.photo),
title: Text('Open Camera'),
),
ListTile(
leading: Icon(Icons.photo_album),
title: Text('Use Picture from Gallery'),
)
],
);
},
onClosing: () => {},
),
關於Scaffold更多的操作可以在Scaffold class裡面找到
大致了解了Scaffold,我們就來針對這次的專案需求實地更改程式碼吧:
移除不必要的FloatingButton
清空頁面主體和計數器邏輯,先用空白的區塊(Container)代替
新增底部的bottomNavigationBar並新增三個頁面選項
新增底部bottomNavigationBar的設定
selectedItemColor
: 項目被選取時呈現的顏色selectedFontSize
: 項目被選取時呈現的字體大小unselectedFontSize
: 項目未被選取時呈現的字體大小unselectedItemColor
:項目未被選取時呈現的字體顏色currentIndex
: 目前被選取的是第幾個項目BottomNavigationBarType
: 定義項目大小是固定(BottomNavigationBarType.fixed
)或浮動(BottomNavigationBarType.shift
),更動AppBar標題為:「今日照片」
本次改動的相關程式碼放在 我的github,見Day9
相關commit
頁面呈現
今天我們看到了:
Scaffold
:快速地組織一個頁面的結構
appBar
:頁面上方橫幅body
:頁面主體floatingButton
:頁面懸浮按鈕bottomNavigationBar
:底部的導頁選單drawer
:側邊欄bottomSheet
:上滑式選單明天我們一起來看看頁面的狀態管理,了解StatelessWidget
和StatefuleWidget
!