每日一言:?我們的手中,握著的可能是失敗的種子,也可能是成功的無限潛能,答案需要我們自己選擇:隨波逐浪將一事無成,全力以赴便會(huì)前程錦繡。讓瞬間創(chuàng)造奇跡,成功從珍惜時(shí)間開始!
原創(chuàng):http://liuwangshu.cn/flutter/primer/4-basics-widget.html
前言
學(xué)完了Dart語(yǔ)言,接下來就可以學(xué)習(xí)Widget了,F(xiàn)lutter的UI界面就是由Widget組成的,Widget的數(shù)量繁多,因此我會(huì)用幾篇文章來專門介紹它,本篇就來介紹Basics Widget。
1.什么是Widget
Flutter的Widget的設(shè)計(jì)靈感來自于React,主要目的就是使用Widget構(gòu)建UI。Widget根據(jù)其當(dāng)前配置和狀態(tài)來描述視圖,當(dāng)Widget的狀態(tài)發(fā)生更改時(shí),Widget會(huì)重建其描述。framework將根據(jù)前面的描述進(jìn)行對(duì)比,以確定底層渲染樹從一個(gè)狀態(tài)轉(zhuǎn)換到下一個(gè)狀態(tài)所需的最小更改。
在Flutter中,除了Basics 的文本、圖片、卡片、輸入框這些基礎(chǔ)控件,布局方式和動(dòng)畫等也都是由Widget組成的。通過使用不同類型的Widget,就可以實(shí)現(xiàn)復(fù)雜的界面。
Widget可以翻譯為部件,粗略的相當(dāng)于Android中的View。Widget和View不同的是:Widget具有不同的生命周期:它是不可變的,每當(dāng)Widget或者其狀態(tài)發(fā)生變化時(shí),F(xiàn)lutter的框架都會(huì)創(chuàng)建一個(gè)新的Widget實(shí)例樹。相比之下,Android中的View會(huì)被繪制一次,并且在invalidate調(diào)用之前不會(huì)重繪。
2.Widget的分類
Widget的分類有很多類別,每個(gè)類別下面又包含很多Widget,主要包括以下幾種類別:
Basics:在構(gòu)建第一個(gè)Flutter應(yīng)用程序之前,需要知道的Basics Widget。
Material Components:Material Design風(fēng)格的Widget。
Cupertino:iOS風(fēng)格的Widget。
Accessibility:輔助功能Widget。
Animation and Motion:動(dòng)畫和動(dòng)作Widget。
Async:Flutter應(yīng)用程序的異步Widget。
Input:除了在Material Components和Cupertino中的輸入Widget外,還可以接受用戶輸入的Widget。
Interaction Models:響應(yīng)觸摸事件并將用戶路由到不同的視圖中。
Layout:用于布局的Widget。
Painting and effects:不改變布局、大小、位置的情況下為子Widget應(yīng)用視覺效果。
Scrolling:滾動(dòng)相關(guān)的Widget。
Styling:主題、填充相關(guān)Widget。
Text:顯示文本和文本樣式。
Basics有些特殊,它是由Flutter官方從其他的Widget分類中選取的一些Widget組成的,這些Widget是官方建議開發(fā)者構(gòu)建第一個(gè)Flutter應(yīng)用程序之前,需要知道的,目的是讓開發(fā)者更快的入門。比如Row屬于Layout分類,它就被選進(jìn)了Basics中。本文遵循了Flutter官方的意圖,首先介紹Basics(Basics Widget)。
Widget更多的是以組合的形式存在,比如Container是屬于Layout中的一個(gè)Widget,而Container又由LimitedBox、 ConstrainedBox、Align、 Padding、 DecoratedBox、Transform部件組成。 如果要實(shí)現(xiàn)Container的自定義效果,可以組合上面這些Widget以及其他簡(jiǎn)單的Widget,而不是將Container進(jìn)行子類化實(shí)現(xiàn)。
3.Widget的狀態(tài)分類
在Android中,我們可以通過直接更改View來更新視圖。但是在Flutter中,Widget是不可變的并且不會(huì)直接更新,而是必須使用Widget的狀態(tài)。
Widget有兩種狀態(tài)分類分別是無狀態(tài)的StatelessWidget和有狀態(tài)的StatefulWidget,StatelessWidget是不可變的,設(shè)置以后就不可再變化,所有的值都是最終的設(shè)置。StatefulWidget可以保存自己的狀態(tài),但是Widget是不可變的,因此需要配合State來保存狀態(tài)。
State擁有自己的聲明周期,如下所示:
名稱狀態(tài)
initStatecreate之后被insert到渲染樹時(shí)調(diào)用的,只會(huì)調(diào)用一次
didChangeDependenciesstate依賴的對(duì)象發(fā)生變化時(shí)調(diào)用
didUpdateWidgetWidget狀態(tài)改變時(shí)候調(diào)用,可能會(huì)調(diào)用多次
build構(gòu)建Widget時(shí)調(diào)用
deactivate當(dāng)移除渲染樹的時(shí)調(diào)用
disposeWidget即將銷毀時(shí)調(diào)用
4.根Widget的種類
上面的MaterialApp就是一個(gè)根Widget,也就是Flutter應(yīng)用程序的第一個(gè)Widget,根Widget有以下幾種:
WidgetsApp: 如果需要自定義風(fēng)格,可以使用WidgetsApp。
MaterialApp:Material Design風(fēng)格的Widget。
CupertinoApp iOS風(fēng)格的根Widget。
如果公司沒有特殊要求,這里建議使用MaterialApp做為根Widget就可以了。
5.Basics Widget
Basics Widget也就是Basics,主要有以下幾種:
Container:一個(gè)便利的容器Widget,可以設(shè)置Widget的背景、尺寸、定位。
Row:在水平方向上布置子窗口Widget列表。
Column:在垂直方向上布置子窗口Widge列表。
Image:顯示圖像的Widget
Text:?jiǎn)我粯邮降奈谋尽?/p>
Icon:符合Material Design設(shè)計(jì)規(guī)范的圖標(biāo)
RaisedButton:符合Material Design設(shè)計(jì)規(guī)范的凸起按鈕。
Scaffold:實(shí)現(xiàn)Basics 的Material Design布局結(jié)構(gòu)。
Appbar:Material Design的應(yīng)用欄。
FlutterLogo:以Widget形式來展示一個(gè)Flutter圖標(biāo),可以調(diào)整樣式。
Placeholder:繪制一個(gè)框,為將來添加的Widget的占位。
這里選擇一些我們必須要掌握的Basics Widget來進(jìn)行講解。
5.1 代碼模板和主題
為了更好的理解這些Basics Widget,我們需要寫一些例子,這些例子需要一個(gè)代碼模板,方便測(cè)試和學(xué)習(xí)。
上面的代碼是稍微改動(dòng)了官方的Hello World代碼,便于測(cè)試,具體的代碼含義已經(jīng)在Flutter基礎(chǔ)(二)Flutter開發(fā)環(huán)境搭建和Hello World中講過了,這里結(jié)合本文要講的內(nèi)容再說點(diǎn)細(xì)節(jié)。注釋1處的MaterialApp屬于Material Components類別中的Widget,MaterialApp中包含了實(shí)現(xiàn)Material Design的應(yīng)用程序所需要的Widget。
注釋2和3處的Scaffold和AppBar同樣也是Material Components類別中的Widget,Scaffold實(shí)現(xiàn)了Material Design布局結(jié)構(gòu),AppBar是Material Design的應(yīng)用欄,它們會(huì)在下一篇文章介紹Material Components時(shí)進(jìn)行講解。效果如下圖所示:
5.2 文本
在4.1小節(jié)中已經(jīng)用了Text,還可以定義樣式:
這次為了便于理解列出了全部的代碼,此后的舉例只列出改變的部分。
通過TextStyle來定義文本的樣式,效果如下:
5.3 圖片
Image的構(gòu)造函數(shù)有多種:
new Image:從ImageProvider獲取圖片
new Image.asset:使用key從AssetBundle獲取圖片
new Image.network:加載網(wǎng)絡(luò)圖片
new Image.file:從文件中獲取圖片
new Image.memory:用于從Uint8List獲取圖片
Image的屬性有很多種,主要的屬性為fit,用于表示圖片的填充模式,參數(shù)類型為BoxFit,BoxFit的取值主要有以下幾種,示例圖片來自flutter官方。
contain
全圖顯示,保持原比例。
cover
全圖充滿,可能拉伸也可能被裁剪
fill
全圖顯示,通過拉伸來充滿目標(biāo)框
fitHeight
圖片高度充滿目標(biāo)框,可能拉伸也可能被裁剪
fitWidth
圖片寬度充滿目標(biāo)框,可能拉伸也可能被裁剪
none
保持圖片的原始大小,剪裁掉位于目標(biāo)框外的圖片部分
scaleDown
與contain縮小圖像的方式相同,只不過會(huì)在必要時(shí)縮小以確保圖片完全在目標(biāo)框內(nèi),如果不縮小等同于none。
效果如下圖所示:
5.4 凸起按鈕
凸起按鈕RaisedButton是符合Material Design設(shè)計(jì)規(guī)范的按鈕,可以通過onPressed來回調(diào)按鈕的點(diǎn)擊。
除了使用RaisedButton,flutter還提供了其他的按鈕,比如FlatButton、IconButton、FloatingActionButton等等,它們的使用方法和RaisedButton大同小異,這里就不再贅述。
5.5 其他Widget
Basics Widget中的還有Row、Column、Container等Widget,這里簡(jiǎn)單介紹下。
Row
Row用于在水平方向顯示數(shù)組中的子元素Widget。
垂直方向顯示數(shù)組中的子元素Widget用Column,使用方法和Row一樣。這里需要提到的是Expanded,可以用Expanded來配合Row和Column使用,用來填充剩余的空間。
其中的Expanded的作用是在自己的尺寸范圍內(nèi)縮放并且調(diào)整child位置,使得child適合其尺寸。FlutterLogo是Basics Widget中的一種,用于展示Flutter圖標(biāo)。使用flex可以調(diào)整兩個(gè)Expanded的占比。
Container
一個(gè)便利的容器Widget,可以設(shè)置Widget的背景、尺寸、定位。描述起來有些抽象,可以理解它和Android中的ViewGroup差不多。
Container的padding和margin屬性和Android中的作用是類似的:
總結(jié)
本文主要介紹了什么是Widget、Widget的分類、Basics Widget。因?yàn)閃idget的數(shù)量繁多,官方將Widget進(jìn)行了分類,并將需要先了解的Widget歸入到了Basics Widget中,后續(xù)文章會(huì)介紹其他的Widge分類。
原創(chuàng):http://liuwangshu.cn/flutter/primer/4-basics-widget.html