新聞中心
Flutter(六)Android與Flutter混合開發(fā)(Hybird)
如果我們目前的項目是Android的,但是接下來我們希望部分頁面可以使用Flutter進行開發(fā),甚至我們希望在Native頁面中嵌入FlutterUI組件,那么我們該如何實現(xiàn)呢?
創(chuàng)新互聯(lián)專注于紫云企業(yè)網(wǎng)站建設,響應式網(wǎng)站建設,購物商城網(wǎng)站建設。紫云網(wǎng)站建設公司,為紫云等地區(qū)提供建站服務。全流程定制網(wǎng)站開發(fā),專業(yè)設計,全程項目跟蹤,創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務
假設你現(xiàn)在Android項目的目錄的結構是這樣的
這時候如果你想創(chuàng)建一個Flutter模塊,使得Android模塊和Flutter模塊之間可以進行交互,我們可以通過Android Studio新建一個Flutter Module,具體過程是:File — New — New Module ,之后選擇Flutter Module,指定Project Location的路徑為
也就是說,最終你的項目結構會是這樣的
接下來在Android Module的 build.gradle 文件中添加flutter依賴
先創(chuàng)建一個Flutter頁面
這里比較重要的是 window.defaultRouteName 這個字段,這個字段可以接收從Native傳遞過來的參數(shù) (下文我們會介紹原生傳遞參數(shù)的方法),也就是說通過這個字段我們就可以進行Flutter頁面的路由的分發(fā)
我們可以直接在Android的 MainActivity 中啟動一個 FlutterActivity ,這里的 initialRoute 方法中傳遞的參數(shù)就對應Flutter層的 window.defaultRouteName
注意:需要在 AndroidManifest.xml 注冊 FlutterActivity
自己創(chuàng)建一個 FlutterAppActivity 繼承自 FlutterActivity
在 MainActivity 中啟動 FlutterAppActivity (另外別忘了在 AndroidManifest.xml 中注冊 FlutterAppActivity )
兩種啟動方式的區(qū)別
如果單純只是想打開一個Flutter頁面,兩種方式實際上基本沒有太大區(qū)別,第一種方式也許還會更簡單一點。但是,在Flutter開發(fā)中,我們往往還需要開發(fā)一些Native插件供Flutter調用,如果使用復寫 FlutterActivity 的方式更有利于我們在 FlutterActivity 中注冊我們的Native插件,所以實際開發(fā)中一般推薦使用第二種方式
擴展思考
initialRoute 從名稱上看起來是Flutter提供給我們進行Native與Flutter交互的路由跳轉的,但是實際上他就是一個字符串,我們不僅僅可以傳遞一個路由名稱,有時候我們也可以通過這個參數(shù)傳遞一串JSON數(shù)據(jù),然后在Flutter端進行解析,這樣我們就可以通過這個參數(shù)做更多的事情
activity_main.xml
FrameLayout 用于承載Flutter組件
MainActivity.java
使用 FragmentManager 將 FlutterFragment 添加到 FrameLayout 容器中
運行結果
上半部分是原生的TextView,下半部分是Flutter的Text組件
本節(jié)主要介紹了Native和Flutter之間的頁面跳轉,以及同一個頁面中Native與Flutter組件的組合。接下來會介紹如何編寫Android插件與Flutter進行數(shù)據(jù)交互
Flutter是一個什么框架
Flutter是一個移動應用程序的軟件開發(fā)工具包(SDK),具有以下特征:
跨平臺應用的框架,沒有使用WebView或者系統(tǒng)平臺自帶的控件,使用自身的高性能渲染引擎自繪
簡化版的瀏覽器,最大限度在android和ios上統(tǒng)一UI,包括業(yè)務邏輯和用戶體驗
開發(fā)語言使用dart,結合C, C++, 和Skia(2D渲染引擎)構建
支持hot reload,包含著完整的控件和工具鏈
一切皆控件,控件是每個Flutter應用程序的基本構建塊,與分離視圖、控制器、布局和其他屬性的框架不同,F(xiàn)lutter具有一致的統(tǒng)一對象模型:控件。一個控件可以定義:結構元素(比如按鈕或菜單)、風格元素(比如字體或顏色方案)、布局的方面(比如填充)、一些業(yè)務邏輯等
組合大于繼承,控件本身通常由許多小型、單用途的控件組成,結合起來產(chǎn)生強大的效果,類的層次結構是扁平的,以最大化可能的組合數(shù)量
強化版的WebView,框架僅提供一個View層,大部分功能要依賴原生
目前只能夠運行大部分Dart代碼(不能引入dart:mirrors或dart:html庫)
Flutter 啟動頁的前世今生適配歷程
APP 啟動頁在國內(nèi)是最常見也是必備的場景,其中啟動頁在 iOS 上算是強制性的要求,其實配置啟動頁挺簡單,因為在 Flutter 里現(xiàn)在只需要:
一般只要配置無誤并且圖片尺寸匹配,基本上就不會有什么問題, 那既然這樣,還有什么需要適配的呢?
事實上大部分時候 iOS 是不會有什么問題, 因為 LaunchScreen.storyboard 的流程本就是 iOS 官方用來做應用啟動的過渡;而對于 Andorid 而言,直到 12 之前 windowBackground 這種其實只能算“民間”野路子 ,所以對于 Andorid 來說,這其中就涉及到一個點:
所以下面主要介紹 Flutter 在 Android 上為了這個啟動圖做了哪些騷操作~
在已經(jīng)忘記版本的“遠古時期” , FlutterActivity 還在 io.flutter.app.FlutterActivity 路徑下的時候,那時啟動頁的邏輯相對簡單,主要是通過 App 的 AndroidManifest 文件里是否配置了 SplashScreenUntilFirstFrame 來進行判斷。
在 FlutterActivity 內(nèi)部 FlutterView 被創(chuàng)建的時候,會通過讀取 meta-data 來判斷是否需要使用 createLaunchView 邏輯 :
是不是很簡單,那就會有人疑問為什么要這樣做?我直接配置 Activity 的 android:windowBackground 不就完成了嗎?
這就是上面提到的時間差問題, 因為啟動頁到 Flutter 渲染完第一幀畫面中間,會出現(xiàn)概率出現(xiàn)黑屏的情況,所以才需要這個行為來實現(xiàn)過渡 。
經(jīng)歷了“遠古時代”之后, FlutterActivity 來到了 io.flutter.embedding.android.FlutterActivity , 在到 2.5 版本發(fā)布之前,F(xiàn)lutter 又針對這個啟動過程做了不少調整和優(yōu)化,其中主要就是 SplashScreen 。
自從開始進入 embedding 階段后, FlutterActivity 主要用于實現(xiàn)了一個叫 Host 的 interface ,其中和我們有關系的就是 provideSplashScreen 。
默認情況下它會從 AndroidManifest 文件里是否配置了 SplashScreenDrawable 來進行判斷 。
默認情況下當 AndroidManifest 文件里配置了 SplashScreenDrawable ,那么這個 Drawable 就會在 FlutterActivity 創(chuàng)建 FlutterView 時被構建成 DrawableSplashScreen 。
DrawableSplashScreen 其實就是一個實現(xiàn)了 io.flutter.embedding.android.SplashScreen 接口的類,它的作用就是:
之后 FlutterActivity 內(nèi)會創(chuàng)建出 FlutterSplashView ,它是個 FrameLayout。
FlutterSplashView 將 FlutterView 和 ImageView 添加到一起, 然后通過 transitionToFlutter 的方法來執(zhí)行動畫,最后動畫結束時通過 onTransitionComplete 移除 splashScreenView 。
所以整體邏輯就是:
當然這里也是分狀態(tài):
當然這個階段的 FlutterActivity 也可以通過 override provideSplashScreen 方法來自定義 SplashScreen 。
看到?jīng)]有,做了這么多其實也就是為了彌補啟動頁和 Flutter 渲染之間, 另外還有一個優(yōu)化,叫 NormalTheme 。
通過該配置 NormalTheme ,在 Activity 啟動時,就會首先執(zhí)行 switchLaunchThemeForNormalTheme(); 方法將主題從 LaunchTheme 切換到 NormalTheme 。
大概配置完就是如下樣子, 前面分析那么多其實就是為了告訴你,如果出現(xiàn)問題了,你可以從哪個地方去找到對應的點 。
講了那么多, Flutter 2.5 之后 provideSplashScreen 和 io.flutter.embedding.android.SplashScreenDrawable 就被棄用了,驚不喜驚喜,意不意外,開不開心 ?
通過源碼你會發(fā)現(xiàn),當你設置了 splashScreen 的時候,會看到一個 log 警告:
為什么會棄用?
其實這個提議是在 這個 issue 上,然后通過 這個 pr 完成調整。
大概意思就是: 原本的設計搞復雜了,用 OnPreDrawListener 更精準,而且不需要為了后面 Andorid12 的啟動支持做其他兼容,只需要給 FlutterActivity 等類增加接口開關即可 。
也就是2.5之后 Flutter 使用 ViewTreeObserver.OnPreDrawListener 來實現(xiàn)延遲直到加載出 Flutter 的第一幀。
為什么說默認情況? 因為這個行為在 FlutterActivity 里,是在 getRenderMode() == RenderMode.surface 才會被調用,而 RenderMode 又和 BackgroundMode 有關心 。
所以在 2.5 版本后, FlutterActivity 內(nèi)部創(chuàng)建完 FlutterView 后就會執(zhí)行一個 delayFirstAndroidViewDraw 的操作。
這里主要注意一個參數(shù): isFlutterUiDisplayed 。
當 Flutter 被完成展示的時候, isFlutterUiDisplayed 就會被設置為 true。
所以當 Flutter 沒有執(zhí)行完成之前, FlutterView 的 onPreDraw 就會一直返回 false ,這也是 Flutter 2.5 開始之后適配啟動頁的新調整。
看了這么多,大概可以看到其實開源項目的推進并不是一帆風順的,沒有什么是一開始就是最優(yōu)解,而是經(jīng)過多方嘗試和交流,才有了現(xiàn)在的版本,事實上開源項目里,類似這樣的經(jīng)歷數(shù)不勝數(shù):
(1)Flutter記錄之啟動頁
一年半前玩過flutter,忘光光...現(xiàn)在是時候重新拾取了。~
啟動頁一般只放圖片或者加幾行文字。
1、創(chuàng)建好flutter項目之后,在lib文件下面新建launch.dart或xx.dart.
2、在根目錄下新建images文件夾,如已有直接放入圖片
3、flutter_yijiake.iml中加入注入該圖片,并注意空格
4、在根目錄下的test/widget_test.dart中更改默認的啟動頁為當前的啟動頁路徑
5、最后重新設置啟動時的頁面
6、非常簡單的啟動頁面放logo圖片
值得一說的是,flutter框架的UI組件需要已new 組件的形式展開。
Flutter-UI
Tip:顯示文本,有些樣式屬性和android的textView類似,例如對齊、大小、顏色等
Tip:Material庫提供了很多按鈕,例如ElevatedButton、TextButton、OutlinedButton等,這些都是直接或者間接對ButtonStyleButton
的包裝定制,所以大多數(shù)屬性和ButtonStyleButton一樣。另外所有的MaterialButton都有兩個共同特征:1、按下時會有水波動畫 2、都有一個onPress回調方法,若不提供回調方法,則按鈕時禁止狀態(tài),不響應用戶點擊
Tip:使用Image來加載并顯示圖片,Image的數(shù)據(jù)源可以是asset、文件、內(nèi)存或者網(wǎng)絡。ImageProvider是一個抽象類,主要定義了圖片數(shù)據(jù)獲取的接口load( ),從不同的數(shù)據(jù)源中獲取數(shù)據(jù)。如AssetImage可以加載本地圖片資源,NetworkImage可以加載網(wǎng)絡圖片。
為什么Flutter開發(fā)APP性能最接近原生,前端程序員請關注
Flutter是谷歌公司推出的跨終端的開發(fā)框架,支持Android、iOS和WEB終端。1.0版在2018年12月5日發(fā)布,目前的最新版本是1.5,它采用的開發(fā)語言是Dart,Dart也是谷歌開發(fā)的計算機編程語言,語法類似C,是編譯型語言:
hello world例子,打印字符串“Hello World!”:
1、沒有橋接層
React Native、Weex等技術都是跨終端的框架,然而性能跟原生App存在很大差距。這是由于它們的工作原理決定的:
React Native、Weex等技術多了一個橋接層,所以界面渲染會慢一些,由于UI渲染非常頻繁,想要不卡頓,基本上比較難,性能和用戶體驗跟原生代碼有差距。而這恰恰是Flutter的優(yōu)勢所在:
Dart可以被編譯成不同平臺的本地代碼,讓Flutter不通過橋接層直接跟平臺通信,自然性能會快一些。
2、編譯執(zhí)行
JavaScript是解釋執(zhí)行的,Dart是編譯執(zhí)行的,性能誰好一目了然。
3、Flutter Engine虛擬機
Flutter是依靠Flutter Engine虛擬機在iOS和Android上運行的,F(xiàn)lutter Engine使用C/C++編寫,開發(fā)人員通過Flutter框架直接和API在內(nèi)部進行交互,所以具有輸入低延遲和UI渲染高幀速率的特點。除了這特點之外,F(xiàn)lutter還提供了自己的小部件,F(xiàn)lutter小部件是使用從React獲取靈感的現(xiàn)代框架構建的。 中心思想是您使用小部件構建UI。
窗口小部件根據(jù)其當前配置和狀態(tài)描述了它們的視圖。 當窗口小部件的狀態(tài)發(fā)生更改時,窗口小部件會重建其描述,框架將根據(jù)前面的描述進行區(qū)分,以確定底層呈現(xiàn)樹從一個狀態(tài)轉換到下一個狀態(tài)所需的最小更改。可以直接在OS平臺提供的畫布上進行描繪,也就是一些核心類庫直接放到虛擬機里面,調用起來更快。
從它的系統(tǒng)結構可以看出,類似安卓的ART(Android Run Time)虛擬機,同樣采用AOT(Ahead of TIme)技術,會在APP安裝時就編譯成機器語言,不再解釋執(zhí)行,從而優(yōu)化了APP運行的性能。
4、自帶渲染引擎
Flutter使用谷歌自己的Skia渲染引擎,而Android系統(tǒng)自帶Skia引擎,iOS平臺上Flutter也會把Skia引擎打包到APP中,從而實現(xiàn)了高效渲染。而React Native通過橋接層訪問原生UI,操作頻繁就容易出性能問題。
綜合所述,F(xiàn)lutter 是性能最接近原生代碼 的一種開發(fā)框架,未來也會是構建谷歌Fuchsia應用的主要方式,前途不可限量,唯一的問題就是需要學習一門新的語言:Dart,而有Java或者C#語言基礎的程序員會比較容易學習。
標題名稱:flutter寫ui,flutter的
文章鏈接:http://www.ef60e0e.cn/article/dscocgj.html