Flutter是什么
- Flutter是一個基于
Dart語言的跨平臺UI框架,目前支持的平臺有iOS,android,Web,Mac OS,Windows,Linux,強(qiáng)調(diào)這個是因為有部分初學(xué)者沒接觸的時候認(rèn)為Flutter是一門語言,這是不正確的
環(huán)境搭建
- Mac和Linux系統(tǒng)設(shè)備建議使用Homebrew執(zhí)行如下命令安裝,Windows的話,去看教程
brew install flutter
- 安裝完默認(rèn)路徑一般為
/usr/local/Caskroom/flutter/2.2.0/flutter這個樣子 - 網(wǎng)上有一大堆的教程去叫你怎么搭建環(huán)境,這里重復(fù)的原因是因為,如果你去按照網(wǎng)上的教程去搭建環(huán)境,會感覺,很繁瑣,真的很繁瑣,特別是iOS開發(fā)人員,為什么搭建環(huán)境一定要那么多步驟?而Homebrew讓這一切變得很簡單,只需要一行命令,然后等待網(wǎng)絡(luò)下載完成就是了
平臺支持
- 已Android studio為例,創(chuàng)建項目時,默認(rèn)支持iOS和Android,但是可勾選支持Web,Linux和Windows ,Mac OS為不可選,如果需要支持可手動進(jìn)行配置,命令如下,之后再創(chuàng)建項目就可以勾選相應(yīng)的其他平臺
flutter config --enable-windows-desktop
flutter config --enable-macos-desktop
flutter config --enable-linux-desktop
- 如果想要在已有的項目中添加新的平臺,進(jìn)入項目根目錄后執(zhí)行如下命令
flutter create .
組件
概括
Flutter里的組件都是Widget,基本可以分為兩大類
StatefulWidget(可變)和StatelessWidget(不可變),區(qū)別就在于前者可以通過對應(yīng)的State類去改變內(nèi)容,所以每一個StatefulWidget都要對應(yīng)一個State,而后者初始化后就不能再進(jìn)行改變Flutter框架本身的組件風(fēng)格分為兩種
Material和Cupertino,前者是Google的設(shè)計風(fēng)格,看一下安卓設(shè)備大概就能了解到是什么樣子,后者是iOS風(fēng)格也就是Apple的設(shè)計風(fēng)格,網(wǎng)上的教程幾乎都是以Material,我在學(xué)習(xí)的過程中也是使用Material風(fēng)格的組件,不過這些只是Flutter內(nèi)置的供你使用的組件,同一個UI你完全可以用這兩種風(fēng)格分別實現(xiàn)
常用Widget
Flutter中內(nèi)置了幾百個Widget,包含顯示類的文字(Text),圖片(Image)等,也包含不直接顯示的容器類Container,Row,Column等,當(dāng)你入門后,對Flutter有了一定的認(rèn)知,后續(xù)的使用中就是經(jīng)驗的積累,去識記更多的Widget,記得越多,開發(fā)越快,下面介紹幾種常用的Widget,記住這幾個后基本開發(fā)一個簡單的App就沒什么問題了
MaterialApp: 一般用作根Widget,App啟動后,main(入口)函數(shù)中執(zhí)行的方法中需要提供
Scaffold:顧名思義,他是Flutter提供的一個腳手架Widget,自帶抽屜,導(dǎo)航等,方便你快速搭起App的結(jié)構(gòu)
Container:容器類Widget的一種,也是最常用的Widget之一,可以理解為iOS中的UIView
Row:橫向布局容器,加入其中的子Widget會水平排列布局
Column:縱向布局容器,加入其中的子Widget會縱向排列布局
Stack:疊加布局布局容器,加入其中的子Widget會疊加起來排列布局
ListView:市面上幾乎所有的App都會使用的,列表Widget
GridView:卡片,瀑布流布局
Text:文字展示
Image:圖片展示
TextButton:文字按鈕
GestureDetector:如果某個Widget想要響應(yīng)點擊等交互事件,即使它本身不具備交互功能,只要用此Widget包括就可以了
上面這樣的一個布局,覺得是怎樣實現(xiàn)的?
結(jié)構(gòu)是這個樣子的

層級是這個樣子的
響應(yīng)式
在iOS中,iOS的框架本身是不支持響應(yīng)式編程的,如果需要,則要借助第三方框架,比如OC的RAC,Swift的RxSwift等,這些框架由于不是官方提供,只是社區(qū)為了實現(xiàn)響應(yīng)式而基于官方框架開發(fā)的應(yīng)用框架,有相當(dāng)高的額外學(xué)習(xí)成本
而Flutter本身就是支持響應(yīng)式的,這為我們的開發(fā)提供的很大的便利
原生交互
通過前面的介紹我么你知道Flutter本身是一個UI框架,如果涉及到一些非UI的比如相機(jī)拍照,必須要和Native交互調(diào)用硬件能力,那我們就必須和Native進(jìn)行通信,F(xiàn)lutter中提供了三種通信方式
MethodChannel:Flutter 與 Native 端相互調(diào)用,調(diào)用后可以返回結(jié)果,可以 Native 端主動調(diào)用,也可以Flutter主動調(diào)用,屬于雙向通信。此方式為最常用的方式, Native 端調(diào)用需要在主線程中執(zhí)行。
BasicMessageChannel:用于使用指定的編解碼器對消息進(jìn)行編碼和解碼,屬于雙向通信,可以 Native 端主動調(diào)用,也可以Flutter主動調(diào)用。
EventChannel:用于數(shù)據(jù)流(event streams)的通信, Native 端主動發(fā)送數(shù)據(jù)給 Flutter,通常用于狀態(tài)的監(jiān)聽,比如網(wǎng)絡(luò)變化、傳感器數(shù)據(jù)等。
MethodChannel示例:
Flutter端
//Flutter端 初始化消息通道
static const MethodChannel _channel = const MethodChannel('com.methodChannel');
//Flutter調(diào)用
final Map test = await _channel.invokeMethod('methodChannelSend');
iOS端
//swift端 初始化消息通道
let channel = FlutterMethodChannel(name: "com.methodChannel", binaryMessenger: registrar.messenger())
//swift端 接收消息
channel.setMethodCallHandler { [weak vc](call, result) in
if call.method == "methodChannelSend" {
print("flutter給native發(fā)消息\(call.arguments ?? (Any).self)")
}
}
庫和插件
Flutter是一個UI框架,但是一個完整的App不只有UI展示,還有其他的能力,比如上邊提到的硬件調(diào)用,錄音,定位,網(wǎng)絡(luò)請求,狀態(tài)管理,數(shù)據(jù)持久化等等...這些能力中Flutter本身是不提供支持的,但是我們我們可以借助響應(yīng)的庫來實現(xiàn),首先說一下庫和插件的關(guān)系
庫是提供特定能力的開發(fā)工具包,可以是官方提供,也可以是三方提供
插件是特殊的庫,舉個例子,比如僅提供iOS和Android調(diào)用的庫,要知道Flutter支持的平臺不止這兩個
引入庫和插件需要在Flutter項目中的pubspec.yaml中進(jìn)行配置,下面提供一個我的配置截圖:
這里要注意dev_dependencies和dependencies兩者的區(qū)別,前者指的是,只在開發(fā)階段生效,不參與編譯的庫,后者指的是,參與編譯,運行需要依賴的庫,他們是有區(qū)別的,舉個例子build_runner,json_serializable配合使用的話,可以通過注解,結(jié)合如下命令,生成額外的xxx.g.dart文件來幫助我們快速的生成JSON轉(zhuǎn)Model方法,但是xxx.g.dart這個文件只在開發(fā)過程中生成和更新,這個庫的作用也僅僅是生產(chǎn)這個文件,所以build_runner它本身不參與編譯
flutter packages pub run build_runner build
雖然都寫在dependencies中項目也可以正常運行,但是這樣的話打出來的包就會變得大一點,可以,但沒必要
下面舉例一些開發(fā)常用的庫:
-
dio三方網(wǎng)絡(luò)庫 -
webview_flutter官方維護(hù)的webview庫 -
cached_network_image圖片加載庫 -
sqflite基于sqlite的輕量級數(shù)據(jù)庫框架 -
pull_to_refresh下拉刷新上拉加載 -
shared_preferences本地數(shù)據(jù)存儲,適合少量數(shù)據(jù)
圖片資源
- 我們在開發(fā)過程中不免要導(dǎo)入一些靜態(tài)資源,比如圖片,文本文件,音頻文件等,我目前只用到了圖片資源這里也只介紹圖片資源的導(dǎo)入和使用,下面看一下我的圖片引入截圖,同樣是在
pubspec.yaml
注意
pubspec.yaml文件有著嚴(yán)格的格式要求,對齊有問題都會導(dǎo)致你導(dǎo)入失敗,我當(dāng)時就吃了系統(tǒng)模板的虧
混編
以上介紹的都是純Flutter項目,什么意思,就是說整個項目的主體是Flutter編寫,可能部分功能涉及到和Native交互,但是實際上,很多成熟的項目想要體驗Flutter,但是又不敢將整個項目使用Flutter重構(gòu),畢竟這中間是有很大風(fēng)險的,所以我們可以在原生項目中,引入Futter模塊,將Native中的某個小模塊用Flutter開發(fā)來進(jìn)行體驗,這樣做的風(fēng)險我們是可以接受的,下面舉一個iOS和Flutter混編并用cocoapods引入的示例
- 假設(shè)
fluttermoduledemo是一個iOS原生項目
//進(jìn)入到fluttermoduledemo目錄的上一級,執(zhí)行如下命令
flutter create --template module flutter_module
其中
flutter_module為需要導(dǎo)入iOS的Flutter模塊名稱,這個模塊的目錄結(jié)構(gòu)和純Fluter項目的結(jié)構(gòu)幾乎一樣,只不過有幾個文件夾變成了隱藏文件夾,編寫Flutter代碼和在純Flutter項目中沒有區(qū)別下面來看一下iOS項目如何引入
//在iOS項目的Podfile文件中添加如下配置,其中第一行最后的flutter_module,就是上一步創(chuàng)建的Flutter模塊的名稱
flutter_application_path = '../flutter_module'
load File.join(flutter_application_path,".ios","Flutter","podhelper.rb")
install_all_flutter_pods(flutter_application_path);
- iOS使用
//在Delegate中初始化Flutter引擎
lazy var flutterEngine = FlutterEngine(name: "ZMEngine")
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
flutterEngine.run()
GeneratedPluginRegistrant.register(with: self.flutterEngine);
return true
}
//在需要的地方,跳轉(zhuǎn)Flutter模塊
let vc = FlutterViewController(engine:self.flutterEngine, nibName: nil, bundle: nil)
self.present(vc,animated: true, completion: nil);
未完內(nèi)容
- 另外還有一些內(nèi)容也很重要,但是我這里沒有展開說的原因是因為,我現(xiàn)在自己也沒有搞得很明白,僅僅處于會用的階段,比如
Future涉及到Dart的線程機(jī)制,比如狀態(tài)管理等,我聽過一句話唯有深入,才能淺出,而現(xiàn)今我還沒有非常深入,所以干脆就不講,以免誤人子弟,只做一個印象級概括
學(xué)習(xí)參考文檔
Flutter學(xué)習(xí)文檔
Dart學(xué)習(xí)文檔
Flutter Package
結(jié)尾
這個文檔只是我去學(xué)Flutter后遇到的一些問題的理解,以及對Flutter整個框架粗略的概括,并非完整教程,類似于你去看電視劇,你需要一集一集的追下去,然后直到結(jié)局才能窺見全貌,而這個文檔相當(dāng)于一種劇透,或者說劇情的概括,看完之后腦海中與一個大體的輪廓,這個Flutter是個什么東西,然后你可以去詳細(xì)的,認(rèn)真的跟著教程去學(xué)習(xí),豐富輪廓內(nèi)的內(nèi)容。



