翁子欣 吳明暉
摘? 要: Flutter是Google開發(fā)的一種高性能的跨平臺移動UI框架,是一套聚焦于原生體驗的分層架構(gòu)。文章介紹了Flutter的框架特性和實現(xiàn)原理,描述了基于Flutter的圖片風格轉(zhuǎn)換App的設(shè)計過程,對App的 UI設(shè)計、不同狀態(tài)類型的關(guān)鍵Widget設(shè)計等關(guān)鍵開發(fā)步驟進行了詳細說明。開發(fā)實踐表明,基于Flutter框架進行App開發(fā)能夠在不降低用戶體驗的基礎(chǔ)上提高開發(fā)效率。
關(guān)鍵詞: Flutter; UI框架; Widget; 圖片風格轉(zhuǎn)換; 移動應用
中圖分類號:TP399? ? ? ? ? 文獻標識碼:A? ? 文章編號:1006-8228(2020)02-67-04
Design and implementation of image style transfer App based on Flutter
Weng Zixin, Wu Minghui
(School of Computer and Computing Science, Zhejiang University City College, Hangzhou, Zhejiang 310015, China)
Abstract: Flutter is a high performance cross platform mobile UI framework developed by Google, which is a layered architecture focusing on the original experience. This paper introduces the main framework features and implementation principles of Flutter, describes the design process of the image style transfer App based on Flutter, and describes the key development steps such as the UI design of the App and the design of key Widgets with different state types in detail. The development practice shows that the application development based on the Flutter framework can improve the development efficiency without reducing the user experience.
Key words: Flutter; UI framework; Widget; image style transfer; mobile App
0 概述
當前主流的移動應用操作系統(tǒng)包括Android和iOS。其中,AndroidApp的主流開發(fā)平臺為Android Studio和Eclipse,主要開發(fā)語言是Java。iOSApp則利用MacOS端的XCode進行開發(fā),開發(fā)語言為Object-C或Swift。若要開發(fā)一款適用于這兩大系統(tǒng)的App,開發(fā)者需要掌握兩套不同的技術(shù)。這會大大增加研發(fā)成本和維護成本。因此,利用跨平臺框架來開發(fā)移動應用的意義十分重大[1]。
Flutter是Google在2018年2月27日世界移動大會上發(fā)布的一個跨平臺開發(fā)框架。它支持在Android和iOS上快速構(gòu)建高質(zhì)量的原生用戶界面,支持以毫秒級的熱重載更新應用頁面,聚焦于原生體驗的分層架構(gòu),允許用戶完全自定義設(shè)計。兼具眾多優(yōu)點,F(xiàn)lutter這一新興的跨平臺開發(fā)框架迅速進入開發(fā)者的視野,受到業(yè)界的熱烈關(guān)注[2]。
Flutter的特別之處在于,它既不使用WebView也不使用系統(tǒng)原生控件,而是選擇高性能的渲染引擎來畫控件。此外,F(xiàn)lutter只有C/C++代碼編寫的單一層,開發(fā)者能更容易控制系統(tǒng),更方便地讀取或者修改系統(tǒng)的組件、手勢、動畫框架和控件等等[3]。
Flutter頁面中所有的元素均為Widget。Flutter使用自己高性能引擎Skia來繪制Widget。這樣不僅可以保證在Android和iOS上UI的一致性,還可以避免對原生控件依賴而帶來的限制及高昂的維護成本。Skia是Google的一個2D圖形處理函數(shù)庫,包含字型、坐標轉(zhuǎn)換以及點陣圖,有高效能且簡潔的表現(xiàn),并且提供了非常友好的API[4]。
Flutter 采用 Dart編程語言來編譯。Dart語言用預編譯的方式編譯多個平臺的原生代碼。這使得Flutter能直接與平臺通信而不需要執(zhí)行上下文切換的JavaScript橋接器。Dart語言適合Flutter框架的主要原因在于它支持Flutter的兩個關(guān)鍵特性:在開發(fā)階段采用JIT模式,改動無需編譯,極大的節(jié)省了開發(fā)時間;在發(fā)布時可以通過AOT生成高效的ARM代碼以保證應用性能。并且Dart在連續(xù)分配多個對象的時候,所需消耗的資源非常少。Dart虛擬機可以快速分配內(nèi)存給短期生存的對象,使很復雜的UI能在60ms內(nèi)完成一幀的渲染,從而保證了平滑的展示UI滑動及動畫等效果。
1 Flutter框架特性
1.1 Widget
Flutter頁面中所有元素都是Widget。Flutter的Widget是對頁面UI的一種描述,類似于Web中的HTML。應用程序、頁面、布局、視圖、事件、通知、甚至是具體的文本樣式都統(tǒng)一化為Widget可以讓Flutter的代碼更加統(tǒng)一。Flutter在構(gòu)建UI過程中形成了一個類似于iOS視圖樹的Widget樹,如圖1所示。Flutter的控件通常由許多小型、單用途的控件組成而不是擴展現(xiàn)有的控件類。小控件結(jié)合起來產(chǎn)生強大的效果。類的層次結(jié)構(gòu)是扁平的,使可能的組合數(shù)量最大化。
視圖在運行時可能變化,因此Flutter引入了State來管理視圖狀態(tài)。在修改完數(shù)據(jù)后,需要主動調(diào)用setState()來觸發(fā)視圖狀態(tài)的更新。根據(jù)狀態(tài)是否可變,Widget又被分為StatefulWidget和StatelessWidget,兩者都繼承自Widget。其中StatelessWidget是指無可變狀態(tài)的Widget,這類Widget的狀態(tài)只由創(chuàng)建Widget時傳入的參數(shù)決定,一旦創(chuàng)建,其在頁面上展示的效果就不再改變。而StatefulWidget存在可變狀態(tài)。當通過setState()改變狀態(tài)時,F(xiàn)lutter就會重新渲染該Widget。
1.2 布局
主要使用了Row、Column、Container、Expanded、Stack等。Row、Column提供了水平、垂直方向的布局,Stack提供了堆疊方式的布局,各種容器有不同的特性,可根據(jù)實際頁面需求選擇搭配不同的布局。
1.3 插件
Flutter有很多功能強大的插件[5],比如:狀態(tài)管理插件、推送、QQ、事件總線Event Bus、Toast提示、圖片選擇器、圖片加載等。在基于Flutter的圖片風格轉(zhuǎn)換App的設(shè)計與實現(xiàn)中運用到了狀態(tài)管理插件、QQ、圖片選擇器、圖片加載器、圖片緩存等。
2 基于Flutter的UI構(gòu)建
UI構(gòu)造過程經(jīng)歷了從Widget樹轉(zhuǎn)換成Element樹再到最終渲染的RenderObject樹。如圖2所示。
其中,Widget樹主要存放渲染內(nèi)容、視圖布局信息;Element存放上下文,通過Element遍歷視圖樹,Element同時持有Widget和RenderObject;Element是對應Widget在渲染樹的實例化節(jié)點。同一個Widget可以對應渲染樹中的多個Element,類似于一個視圖模板;RenderObject根據(jù)Widget的布局屬性進行l(wèi)ayout,paint Widget傳人的內(nèi)容。另外,在視圖描述Widget和真實渲染的RenderObject的中間設(shè)計的Element層對某一時刻的事件做了匯總和比對,只對真正需要修改的部分同步到真實渲染的RenderObject樹上面,提高了渲染效率。
3 圖像風格轉(zhuǎn)換App設(shè)計
這款App的主要功能是將用戶選擇的圖片按照指定風格轉(zhuǎn)換并展示。用戶可以將轉(zhuǎn)換好的圖片保存至本地相冊或分享至QQ。App的UI界面設(shè)計如圖3。
用戶首先從本地相冊或者使用相機拍攝獲取需要轉(zhuǎn)換風格的圖片。用戶選定圖片后的界面如圖3(a)。點擊不同風格對應窗口中的轉(zhuǎn)換按鈕,等待數(shù)秒后即得到對應風格的目標圖片,效果如圖3(b)所示。用戶可以向上滑動界面觸發(fā)分享功能,將轉(zhuǎn)換好的圖片分享給QQ好友,如圖3(c),也可以下滑界面觸發(fā)保存功能,將轉(zhuǎn)換好的圖片保存至本地相冊,效果如圖3(d)。
根據(jù)需要實現(xiàn)的功能,該App的主要組件為:圖片選擇器、圖片翻頁器、圖片風格轉(zhuǎn)換器、相機按鈕、相冊按鈕以及風格轉(zhuǎn)換按鈕。
圖片選擇器用于管理圖片選擇,將圖片從相機/相冊中導入后轉(zhuǎn)換成MemoryImage類型的圖片保存在內(nèi)存中,如圖4所示。在導入圖片的過程中,可以適當壓縮圖片大小以減少內(nèi)存的占用,并且根據(jù)圖片的EXIF信息把圖片旋轉(zhuǎn)到正常的角度,計算圖片的主要色調(diào),用以確定圖片邊框顏色和按鈕控件的顏色等。圖片翻頁器用于管理各個風格的圖片。圖片風格轉(zhuǎn)換器是狀態(tài)可變的Widget,用于管理圖片轉(zhuǎn)換的狀態(tài)。其通過圖片的轉(zhuǎn)換階段來確定Widget的渲染外觀并確定是否要顯示轉(zhuǎn)換按鈕以及調(diào)用網(wǎng)絡(luò)請求。
4 重要Widget的實現(xiàn)
Widget的主要任務(wù)是實現(xiàn)build函數(shù),定義Widget中其他較低層次的控件,build函數(shù)依次構(gòu)建這些控件即實例化一個或者多個Element對象。通過Element對象實現(xiàn)UI渲染樹,直到底層渲染對象。
Flutter可以在Windows、Linux、Mac上開發(fā),開發(fā)工具可以使用VS Code、Android Studio、IDEA等,本次開發(fā)使用Android Studio,主要因為Android Studio提供的Flutter Inspector工具可以實時審查元素,解決界面的顯示適配問題。下面舉例介紹幾個典型的狀態(tài)可變的Widget與狀態(tài)不可變的Widget的實現(xiàn):
4.1 圖片選擇器(Stateful)
圖片選擇器的構(gòu)造函數(shù):
@override
Widget build(BuildContext context){
print(lastColor);
returnFutureBuilder(
future: MyTools.loadImage(_imgPath),
builder:(BuildContextcontext, AsyncSnapshot
Widget ret;
if(snapshot.hasError){
ret = Text(snapshot.error.toString());
}else{
MyImageData data = snapshot.data;
Switch(snapshot.connectionState){
CaseConnectionState.done:
lastMainColor = data.color.color;
lastTextColor = data.color.color;
lastColor = data.color;
ret=MyPageController(data,styleNames,styleJson);
ret = Text(“l(fā)oading”);
}
}
return new Container(
color: lastMainColor,
child: addButtons(ret,lastColor),
); // Container
},
); //FutureBuilder
}
上述構(gòu)造函數(shù)用于圖片選擇。當導入不同圖片時,該Widget需要被刷新,因此該Widget是有狀態(tài)變化的組件,需要繼承自Statefulwidget類。因為加載和計算圖片的屬性比較耗時,所以使用FutureBuilder對象來觀察這個耗時操作并根據(jù)該操作的不同階段來返回不同的Widget樹。當setState()被調(diào)用時,build方法都會重新執(zhí)行以改變該Widget的狀態(tài)。
4.2 圖片風格轉(zhuǎn)換器(Stateful)
首先用Stack控件構(gòu)造圖片和圖片的高斯模糊化的邊框,然后根據(jù)該控件的狀態(tài)決定是否需要加上轉(zhuǎn)換按鈕。最外層的手勢監(jiān)控控件(GestureDetector)用于監(jiān)視用戶的手勢,當用戶上下滑動界面時,要讓控件產(chǎn)生上下位移的效果。上移觸發(fā)分享的功能,下移觸發(fā)保存的功能。在手勢監(jiān)控控件(GestureDetector)中編寫對應用戶下拉手勢的動畫效果:用AnimationController和Tween線性的觸發(fā)重繪函數(shù)(setState()),使得控件對應用戶下拉手勢,并且在松手之后會有回彈效果。同時,還可以調(diào)用onVerticalDragEnd事件。在用戶完成下拉操作時添加額外動畫。
4.3 圖片翻頁器(Stateless)
使用系統(tǒng)的PageController控件構(gòu)造一個可以左右翻頁用于展示多種轉(zhuǎn)換效果的控件。該控件通過傳入itemBuilder參數(shù)告訴控件如何渲染每頁的內(nèi)容。頭部的Text說明風格的種類,中間的圖片風格轉(zhuǎn)換器控件用于展示圖片。效果如圖5所示。
5 結(jié)束語
Flutter基于Skia引擎使用Dart語言搭建了一套全新的UI框架,底層調(diào)用OpenGL繪制,在Native和Flutter Engine上實現(xiàn)了UI的隔離。開發(fā)者在寫UI代碼時就不用再關(guān)心平臺實現(xiàn),從而實現(xiàn)了跨平臺。此外,F(xiàn)lutter可以通過平臺通道與原生進行靈活通信,渲染效率非常高,其release版的流暢度堪比原生。在排版、圖標、滾動、點擊等方面,F(xiàn)lutter能夠?qū)崿F(xiàn)零差異。Flutter作為一個高效開發(fā)與高性能并存的UI框架,大大提高了移動應用的開發(fā)效率。隨著Google與開源社區(qū)的不斷支持,將會有更多的開發(fā)者感受到利用Flutter框架進行開發(fā)帶來的高效體驗。相信Flutter在跨平臺移動應用開發(fā)中將成為一種新趨勢,受到業(yè)界更加熱烈的關(guān)注。
參考文獻(References):
[1] 金誠.移動應用跨平臺開發(fā)框架的比較分析[J].民營科技, 2018.10:150-152
[2] 彭娟. 跨平臺移動應用開發(fā)技術(shù)研究[J].科學咨詢(科技·管理),2017.27:59.
[3] 周勇,程子清.Flutter的原理深度剖析[J].電腦編程技巧與維護,2018.11:19-21
[4] 杜文. Flutter實戰(zhàn)[EB/OL].https://book.flutterchina.club/,2019-4-26.
[5] KeMao,MarkHarman,YueJia. Robotic Testing of Mobile Apps for Truly Black-Box Automation[J].IEEE Software,2017.34(2):11-16