要說2018年最火的跨端技術,當屬於 Flutter
莫屬,應該沒人質疑吧。一個新的技術的趨勢,最明顯的特徵,就是它必定想把「前浪」拍死在沙灘上。這個前浪,就是"react Native","weex"。目前隨便在搜索引擎上 搜索"Flutter reactNative",就全是這兩個技術的對比,評測。javascript
是的,錯過了react Native
, weex
這些 「炸」 翻前端的技術,不能在錯過 Flutter
了,這年頭,你不會一門,跨端技術,怎麼好意思說本身是【前端】。css
Flutter是谷歌的移動UI框架,能夠快速在iOS和Android上構建高質量的原生用戶界面。 Flutter能夠與現有的代碼一塊兒工做。在全世界... ... html
話說隔壁師兄,「閒魚」 是最先一批與谷歌展開合做,並在重要的商品詳情頁中使用flutter技術上線的BU。一路走來,積累了大量的開發經驗。「閒魚」 flutter 相關文章的都頗有深度,足見功力。前端
Flutter
的web前端同窗來講仍是好了,回到標題,筆者做爲一名傳統 web前端,想從前端最熟悉的視角 「躺」 着把 Flutter
瞭解一遍,不要敬仰,平視它!!!先從興趣開始。java
Flutter 環境的搭建,其實有不少資源能夠參考。這裏就不累述了(知道有不少坑,在後續文章中,有機會把我的遇到的坑彙總一下 )。react
有興趣能夠參考 flutter安裝環境的搭建 , 在這裏建議各位,必定要本身親自搭一下環境,跑一下官方demo, 小馬過河,焉知深淺,本身定的位纔是最準確的。git
有了環境,先配置編輯器。github
而後 建立一個Flutter項目。web
項目建立完成,能夠先用 flutter run 跑一下。segmentfault
flutter run
好了,跑起來了吧,你會看到一個計數的官方示例,點擊加號圖片能夠作加運算。
這時候咱們看項目的project 目錄裏 有一個入口文件叫 main.dart。而後打開 main.dart 就像下面這樣:
( 爲何大家看到代碼比個人長,由於我摺疊了!!! ) 這不是重點,重點是每一個類繼承的都是一個尾號爲Widget
的字符。
聰明的你必定會以爲 Widget
和 Flutter
有着某種神祕的聯繫。
「Binggo!",是的,Flutter
有兩個重型武器,一個叫 Dart
,另外一個就是 Widget
了。
Dart
一切皆來自 Object
, Flutter
的組件皆來自 Widget
。關於強大的Dart,今天暫且不表,後面有時間能夠獨立篇幅來聊聊Dart。
先祭出一張 Flutter
的架構老圖。
在 Flutter
的世界裏,包括views,view controllers,layouts等在內的概念都創建在Widget之上。
Widget
是 Flutter
組件的抽象描述。因此掌握Flutter的基礎就是學會使用 Widget
開始。
在Flutter界面渲染過程分爲三個階段:佈局、繪製、合成,佈局和繪製在Flutter框架中完成,合成則交由引擎負責:
class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding,PaintingBinding, RendererBinding, WidgetsBinding { ... } abstract class Widget extends DiagnosticableTree { ... } abstract class StatelessWidget extends Widget { ... } abstract class StatefulWidget extends Widget { ... } abstract class RenderObjectWidget extends Widget { ... } abstract class Element extends DiagnosticableTree implements BuildContext { ... } abstract class RenderObjectElement extends Element { ... } class StatelessElement extends ComponentElement { ... } class StatefulElement extends ComponentElement { ... }
上面這些類的主要做用以下:
Widget = 樣式(css) + 標記語義(標籤) + 組件化(官方) + 數據綁定(props)
「什麼?這不就是 react 嗎?"
對, React 的概念和Flutter
的Widget
是有相通性的。
「既然有react的概念,難道還有state,setState嗎?「
又對, Flutter 還真有 相似 state 狀態機制的概念,並且也確實有 setState 的方法。
「dome裏有兩個基類,StatelessWidget 和 StatefulWidget 是作什麼用的?」
StatelessWidget 和 StatefulWidget,這裏兩個類特別重要,幾乎全部的組件都是基於他們建立的。StatelessWidget 是狀態不可變的widget,稱爲
無狀態widget
。初始狀態設置之後就不可再變化。若是須要變化須要從新建立。StatefulWidget 能夠保存本身的狀態,稱爲
有狀態widget
。Flutter
首先保存了初始化時建立的State,狀態是經過改變State,來從新構建Widget
樹來進行UI變化。改變狀態的方法,就是咱們用的最多的神器"setState",而單純改變數據是不會引起UI改變的,這個概念和咱們的 React 同樣同樣的。
Flutter
能夠不用記憶這麼多組件基類,只用記住如下式子就能夠, 不誇張的說,熟悉這個式子就能夠開發 Flutter 項目了:爲何不稱爲 「模版」,「標籤」,「element" ,而叫"標記語義",是由於flutter的 widget 結構並不僅是 「模版」,「標籤」,「element"。widget 描述結構更像是 React 的虛擬dom階段,濃縮了相關上下文,以對象化的結構展現。
咱們先來看看,React 建立出來的虛擬dom結構( 僞代碼 ):
var newTree = el('div', {'id': 'container'}, [ el('h1', {style: 'color: red'}, ['simple virtal dom']), el('p', ['Hello, virtual-dom']), el('ul', [el('li'), el('li')]) ])
再來看看,flutter 用Dart 建立的 widget 代碼結構:
Widget build(BuildContext context) { return new Column( children: <Widget>[ new Container( padding: new EdgeInsets.only(top:100.0), child: new Text('這是一個組件') ), new Container( decoration: new BoxDecoration(border: new Border.all(width:1.0,color: Colors.blue)), padding: new EdgeInsets.all(20.0), child: new Text('來自輸入框:'+active) ) ], ); }
是否是這樣看就熟悉不少了。
注:不少前端er 會不習慣這中書寫方式,目前有開發者在社區推進,在編譯前,使用jsx標籤,編譯後再解析成標記樹,好比這個 DSX設計的提案。
雖然jsx->標記樹 還只是提案,但其實能夠幫助咱們更容易理解,此提案想表達的樣式像這樣:
class MyScaffold extends StatelessWidget { build(context) { return <Material> <Column> <MyAppBar title={<Text text='Example title' style={Theme.of(context).primaryTextTheme.title}, />} /> <Expanded> <Center> <Text text='Hello, world!'/> </Center> </Expanded> </Column> </Material>; } }
上面這段 jsx 要是用 Dart 來寫是什麼樣的?以下:
class MyScaffold extends StatelessWidget { @override Widget build(BuildContext context) { return Material( child: Column( children: <Widget>[ MyAppBar( title: Text( 'Example title', style: Theme.of(context).primaryTextTheme.title, ), // Text ), // MyAppBar Expanded( child: Center( child: Text('Hello, world!'), ), // Center ), // Expanded ], // <Widget>[] ), // Column ); // Material } }
雖然 Flutter
與 react 這麼類比多少有些牽強,但能夠我的總結一些方法,方便理解:
Flutter
項目後,自動追加上去的,像 jsx 語言的標籤封閉,方便發現標註的起始節點。對於 Flutter
樣式的理解,能夠查看官方的這篇文檔,也是一樣用類比的方式,很直觀的瞭解,HTML、css樣式和 flutter
之間的聯繫.
能夠參考這裏:
https://flutter.io/docs/get-s...
https://flutterchina.club/web...
筆者摘選其中樣例的重點部分,對比展現來講明( 因爲篇幅問題, 父子關係css 結構,用tab方式來表示 ):
.demo1 { background-color: #e0e0e0; width: 320px; height: 240px; font: 900 24px Georgia; letter-spacing: 4px; text-transform: uppercase; }
var demo1 = new Container( child: new Text( "Lorem ipsum".toUpperCase(), // 對應 左邊的文本轉換大小寫 style: new TextStyle( // 對應 左邊的 font fontSize: 24.0 fontWeight: FontWeight.w900, fontFamily: "Georgia", letterSpacing: 4.0, ), ), width: 320.0, // 對應 左邊的 width height: 240.0, // 對應 左邊的 height color: Colors.grey[300], // 對應 左邊的 background-color );
.demo2 { display: flex; align-items: center; justify-content: center; }
var demo2 = new Container( child: new Center( // 對應左邊的整個 flex 屬性 child: new Text("Lorem ipsum") ) ); );
.container{ width:300px .demo3 { width: 100%; max-width: 240px; } }
// 對於嵌套容器,若是父級的寬度小於子級寬度,則子級容器將自行調整大小以匹配父級。 var container = new Container( child: new Center( child: new Text("Lorem ipsum"), decoration: new BoxDecoration( ... ), // constraints屬性,建立一個新的BoxConstraints來設置minWidth或maxWidth width: 240.0, // 對應左邊的 max-width ), width:300.0 ),
.box { transform: rotate(15deg); }
var container = new Container( // gray box child: new Transform( // 對應左邊的 transform child: new Container( ... ), alignment: Alignment.center, // 對應左邊的 transform transform: new Matrix4.identity() // 對應左邊的 transform ..rotateZ(15 * 3.1415927 / 180), ), ) );
.box { transform: scale(1.5); }
var container = new Container( // gray box child: new Transform( // 對應左邊的 transform child: new Container( ... ), alignment: Alignment.center, // 對應左邊的 transform的中心 transform: new Matrix4.identity() // 對應左邊的 transform ..scale(1.5), ), ) );
.greybox { position: relative; .redbox { position: absolute; top: 24px; left: 24px; } }
var container = new Container( // grey box child: new Stack( // 相對跟容器位置 relative children: [ new Positioned( // 相對父容器位置 absolute child: new Container( ... ), left: 24.0, top: 24.0, )], ) );
.redbox { background: linear-gradient(180deg, #ef5350, rgba(0, 0, 0, 0) 80%); }
var container = new Container( // grey box child: new Center( child: new Container( // red box child: new Text( ... ), decoration: new BoxDecoration( gradient: new LinearGradient( // 對應左邊的 background: linear-gradient begin: const Alignment(0.0, -1.0), end: const Alignment(0.0, 0.6), colors: <Color>[ const Color(0xffef5350), const Color(0x00ef5350) ], ), ) ), ) );
.box { border-radius: 8px; }
var container = new Container( // grey box child: new Center( child: new Container( // red circle child: new Text( ... ), decoration: new BoxDecoration( borderRadius: new BorderRadius.all( const Radius.circular(8.0), ), ) ), ) );
.box { box-shadow: 0 2px 4px rgba(0, 0, 0, 0.8), 0 6px 20px rgba(0, 0, 0, 0.5); }
var container = new Container( // grey box child: new Center( child: new Container( // red box child: new Text( ... ), decoration: new BoxDecoration( boxShadow: <BoxShadow>[ // 對應左邊的 box-shadow new BoxShadow ( color: const Color(0xcc000000), offset: new Offset(0.0, 2.0), blurRadius: 4.0, ), new BoxShadow ( color: const Color(0x80000000), offset: new Offset(0.0, 6.0), blurRadius: 20.0, ), ], ) ), ) );
.circle { text-align: center; width: 160px; height: 160px; border-radius: 50%; }
var container = new Container( // grey box child: new Center( child: new Container( // red circle child: new Text( ... ), decoration: new BoxDecoration( color: Colors.red[400], shape: BoxShape.circle, // 畫圓和圓角不太同樣,用的是BoxShape繪製圖像能力 ), width: 160.0, height: 160.0, ), ) );
// css 的內聯結構 .greybox { font: 900 24px Roboto; .redbox { em { font: 300 48px Roboto; font-style: italic; } } }
var container = new Container( // grey box child: new Center( child: new Container( // red box child: new RichText( text: new TextSpan( style: bold24Roboto, children: <TextSpan>[ new TextSpan(text: "Lorem "), // 繼承內聯樣式 new TextSpan( text: "ipsum", style: new TextStyle( // 具備自定義樣式的單獨樣式 fontWeight: FontWeight.w300, fontStyle: FontStyle.italic, fontSize: 48.0, ), ), ], ), ), ), ) );
官方的widgets目錄
點擊每個card後,裏面還有子card, 以一個展開的緯度來看,是這樣的:
這真是一個龐大的組件系統,這不是社區提供的,而是官方的。
flutter 團隊事無鉅細的實現了目前市面上基本上能見到的組件方式和類型。
我的認爲這樣作優缺點並存的。
先說缺點:
StatelessWidget:
![]()
StatefulWidget
Flutter
官方就不建議使用第三方組件,這個也未有定論。再說優勢:
樂高
,Flutter
就是顆粒標準統一的樂高
。3.天下之勢,分久必合,合久必分。
flash
一統pc頁面的富媒體時代,後被喬布斯和H5瓦解;H5
的繁盛和框架、語法、構建模式的亂戰;實際的 Flutter Widget
要複雜的更多的多,在眼花繚亂的 Widget
組件中,筆者想用本身的一些理解,去粗取精,來逐步理解 Flutter
這個新傢伙 ,文中有理解不到位的地方,歡迎你們指正。
筆者團隊也正在開發一套《Flutter GO》的APP,幫助你們熟悉複雜的 Flutter Widget
。
原文連接更多學習 Flutter的小夥伴,歡迎入QQ羣 Flutter Go :679476515
《Flutter GO》項目地址 alibaba/flutter-go