前言:距離上次寫Flutter已經(jīng)2個月過去了航罗,這兩天打開Flutter項目一看,既有些熟悉又有些陌生毫痕。由于目前的項目是用Swift寫的征峦,項目有點小忙。忙只是接口消请,保持持續(xù)的輸入輸出才是重中之重栏笆。要是丟了Flutter這塊的知識儲備,覺得實在是太可惜梯啤,于是決定重新開啟啟程之路竖伯。早上提前到辦公室學(xué)習(xí)半小時,中午再利用中午空擋時間學(xué)習(xí)半小時因宇。 這樣光工作的閑魚時間一個月算下來110個小時七婴。。
Let's learn together察滑!
一打厘、創(chuàng)建工程
二、開始Flutter代碼
2.1 Hello World的實現(xiàn)
2.2 代碼分析
2.2.1 runApp和Widget
2.2.2. Material設(shè)計風(fēng)格
2.3 代碼優(yōu)化
2.3.1 改進界面樣式及結(jié)構(gòu)
2.4 代碼重構(gòu)
2.4.1. 創(chuàng)建自己的Widget
2.4.2. StatelessWidget
2.4.3. 重構(gòu)案例代碼
一贺辰、創(chuàng)建工程
創(chuàng)建功能之后會有一些默認的代碼户盯,直接運行,我們會發(fā)現(xiàn)這是一個計數(shù)器的案例程序饲化,點擊右下角的 + 符號莽鸭,上面顯示的數(shù)字會遞增;
默認項目分析:
在目錄下有一個lib文件夾吃靠,里面會存放我們編寫的Flutter代碼硫眨;
打開發(fā)現(xiàn)里面有一個main.dart,它是我們Flutter啟動的入口文件巢块,里面有main函數(shù)礁阁;
我們第一次接觸main.dart中的代碼,可能會發(fā)現(xiàn)很多不認識的代碼族奢,不知道這個內(nèi)容是如何編寫出來的姥闭;
作為初學(xué)者,我的建議是將其中所有的代碼全部刪除掉越走,從零去創(chuàng)建里面的代碼棚品,這樣我們才能對Flutter應(yīng)用程序的結(jié)構(gòu)非常清晰;
二廊敌、開始Flutter代碼
2.1 Hello World的需求實現(xiàn)(簡單粗暴型實現(xiàn)方式)
import 'package:flutter/material.dart';
main(List<String> args) {
runApp(Text("Hello World", textDirection: TextDirection.ltr));
}
疑惑
- 導(dǎo)入的Material是什么呢南片?
- 我們在main函數(shù)中調(diào)用了一個runApp()函數(shù)又是什么呢?
2.2 代碼分析
2.2.1 runApp和Widget
runApp是Flutter內(nèi)部提供的一個函數(shù)庭敦,當(dāng)我們啟動一個Flutter應(yīng)用程序時就是從調(diào)用這個函數(shù)開始的
我們可以點到runApp的源碼,查看到該函數(shù)
void runApp(Widget app) {
...省略代碼
}
該函數(shù)讓我們傳入一個東西:Widget薪缆?
對Widget的理解:
- 做過Android秧廉、iOS等開發(fā)的人群伞广,喜歡將它翻譯成控件;
- 做過Vue疼电、React等開發(fā)的人群嚼锄,喜歡將它翻譯成組件;
- 如果我們使用Google蔽豺,Widget翻譯過來應(yīng)該是小部件区丑;
Widget到底什么東西呢?
我們學(xué)習(xí)Flutter修陡,從一開始就可以有一個基本的認識:Flutter中萬物皆Widget(萬物皆可盤)沧侥;
在我們iOS或者Android開發(fā)中,我們的界面有很多種類的劃分:應(yīng)用(Application)魄鸦、視圖控制器(View Controller)宴杀、活動(Activity)、View(視圖)拾因、Button(按鈕)等等旺罢;
但是在Flutter中,這些東西都是不同的Widget而已绢记;
也就是我們整個應(yīng)用程序中所看到的內(nèi)容幾乎都是Widget扁达,甚至是內(nèi)邊距的設(shè)置,我們也需要使用一個叫Padding的Widget來做蠢熄;
runApp函數(shù)讓我們傳入的就是一個Widget:
但是我們現(xiàn)在沒有Widget跪解,怎么辦呢?
我們可以導(dǎo)入Flutter默認已經(jīng)給我們提供的Material庫护赊,來使用其中的很多內(nèi)置Widget惠遏;
2.2.2. Material設(shè)計風(fēng)格
material是什么呢?
material是Google公司推行的一套設(shè)計風(fēng)格骏啰,或者叫設(shè)計語言节吮、設(shè)計規(guī)范等;
里面有非常多的設(shè)計規(guī)范判耕,比如顏色透绩、文字的排版、響應(yīng)動畫與過度壁熄、填充等等帚豪;
在Flutter中高度集成了Material風(fēng)格的Widget;
在我們的應(yīng)用中草丧,我們可以直接使用這些Widget來創(chuàng)建我們的應(yīng)用(后面會用到很多)狸臣;
Text小部件分析:
我們可以使用Text小部件來完成文字的顯示;
我們發(fā)現(xiàn)Text小部件繼承自StatelessWidget昌执,StatelessWidget繼承自Widget烛亦;
所以我們可以將Text小部件傳入到runApp函數(shù)中
屬性非常多诈泼,但是我們已經(jīng)學(xué)習(xí)了Dart語法,所以你會發(fā)現(xiàn)只有this.data屬性是必須傳入的煤禽。
2.3 代碼優(yōu)化
需求改進:
- 我們可能希望文字居中顯示铐达,并且可以大一些;
- 居中顯示: 需要使用另外一個Widget檬果,Center瓮孙;
- 文字大一些: 需要給Text文本設(shè)置一些樣式;
2.3.1 改進界面樣式及結(jié)構(gòu)
正常的App頁面應(yīng)該有一定的結(jié)構(gòu)选脊,比如通常都會有導(dǎo)航欄杭抠,會有一些背景顏色等
在開發(fā)當(dāng)中,我們并不需要從零去搭建這種結(jié)構(gòu)化的界面知牌,我們可以使用Material庫祈争,直接使用其中的一些封裝好的組件來完成一些結(jié)構(gòu)的搭建
import 'package:flutter/material.dart';
main(){
runApp(
MaterialApp(
debugShowCheckedModeBanner:false ,
home: Scaffold(
appBar: AppBar(
title: Text("Flutter"),
),
body: Center(
child: Text(
"Hello World",
textDirection: TextDirection.ltr,
style: TextStyle(fontSize: 20),
),
),
),
),
);
}
代碼解讀
在最外層包裹一個MaterialApp
這意味著整個應(yīng)用我們都會采用MaterialApp風(fēng)格的一些東西,方便我們對應(yīng)用的設(shè)計角寸,并且目前我們使用了其中兩個屬性菩混;
title:這個是定義在Android系統(tǒng)中打開多任務(wù)切換窗口時顯示的標(biāo)題;(暫時可以不寫)
home:是該應(yīng)用啟動時顯示的頁面扁藕,我們傳入了一個Scaffold沮峡;
Scaffold是什么呢?
翻譯過來是腳手架亿柑,腳手架的作用就是搭建頁面的基本結(jié)構(gòu)邢疙;
所以我們給MaterialApp的home屬性傳入了一個Scaffold對象,作為啟動顯示的Widget望薄;
Scaffold也有一些屬性疟游,比如appBar和body;
appBar是用于設(shè)計導(dǎo)航欄的痕支,我們傳入了一個title屬性颁虐;
body是頁面的內(nèi)容部分,我們傳入了之前已經(jīng)創(chuàng)建好的Center中包裹的一個Text的Widget卧须;
2.4 代碼重構(gòu)
2.4.1 創(chuàng)建自己的Widget
當(dāng)代碼嵌套過多時另绩,結(jié)構(gòu)很容易看不清晰。學(xué)會拆分以及抽取使其代碼可讀性更高花嘶,乃是重中之重K褡选!椭员!
2.4.2 StatelessWidget
StatelessWidget通常是一些沒有狀態(tài)(State车海,也可以理解成data)需要維護的Widget:
它們的數(shù)據(jù)通常是直接寫死;
從parent widget中傳入的而且一旦傳入就不可以修改隘击;
我們來看一下創(chuàng)建一個StatelessWidget的格式:
1侍芝、讓自己創(chuàng)建的Widget繼承自StatelessWidget喘沿;
2、StatelessWidget包含一個必須重寫的方法:build方法竭贩;
class MyStatelessWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return <返回我們的Widget要渲染的Widget,比如一個Text Widget>;
}
}
build方法的解析:
Flutter在拿到我們自己創(chuàng)建的StatelessWidget時莺禁,就會執(zhí)行它的build方法留量;
我們需要在build方法中告訴Flutter,我們的Widget希望渲染什么元素哟冬,比如一個Text Widget楼熄;
StatelessWidget沒辦法主動去執(zhí)行build方法,當(dāng)我們使用的數(shù)據(jù)發(fā)生改變時浩峡,build方法會被重新執(zhí)行可岂;
build方法什么情況下被執(zhí)行呢?:
1翰灾、當(dāng)我們的StatelessWidget第一次被插入到Widget樹中時(也就是第一次被創(chuàng)建時)缕粹;
2、當(dāng)我們的父Widget(parent widget)發(fā)生改變時纸淮,子Widget會被重新構(gòu)建平斩;
3、如果我們的Widget依賴InheritedWidget的一些數(shù)據(jù)咽块,InheritedWidget數(shù)據(jù)發(fā)生改變時绘面;
2.4.3 重構(gòu)案例代碼
- 整個代碼都是一些數(shù)據(jù)展示,沒有數(shù)據(jù)的改變侈沪,使用StatelessWidget即可
- 為了體現(xiàn)更好的封裝性揭璃,對代碼進行了兩層的拆分,讓代碼結(jié)構(gòu)看起來更加清晰
重構(gòu)后的代碼如下:
import 'package:flutter/material.dart';
//只有一行代碼 可用箭頭函數(shù)
main() =>( runApp(MyApp()));
/*
* Widget:
* 有狀態(tài)的Widget:StatefulWidget 在運行過程中有些狀態(tài)(data)需要改變
* 無狀態(tài)的Widget:StatelessWidget 內(nèi)容是確定滅有狀態(tài)(data)的改變
* */
//寫死的東西則選用StatelessWidget繼承
class MyApp extends StatelessWidget{
//StatelessWidget中的 有個抽象方法 build 必須要實現(xiàn)
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner:false ,
home: Scaffold(
appBar: AppBar(
title:Text("Flutter"),
),
body: HomeBody(),
),
);
}
}
class HomeBody extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Center(
child: Text("Hello World",
style: TextStyle(
color: Colors.red,
fontSize:32.0,
)
),
);
}
}