1.Flutter Widget框架
Flutter Widget採用現代響應式框架構建,這是從React中獲得的靈感,中心思想是用widget構建你的UI。Widget描述了他們的視圖在給定其當前配置和狀態時應該看起來像什麼。當widget的狀態發生變化時,widget會重新構建UI,Flutter會對比前後變化的不同, 以確定底層渲染樹從一個狀態轉換到下一個狀態所需的最小更改(譯者語:類似於React/Vue中虛擬DOM的diff算法)。
Flutter是一款行動應用程式SDK,一份代碼可以同時生成iOS和Android兩個高性能、高保真的應用程式。Flutter目標是使開發人員能夠交付在不同平臺上都感覺自然流暢的高性能應用程式。我們兼容滾動行為、排版、圖標等方面的差異。為什麼要用Flutter?
Flutter有什麼優勢?它可以幫助你:
提高開發效率
同一份代碼開發iOS和Android用更少的代碼做更多的事情輕鬆迭代在應用程式運行時更改代碼並重新加載(通過熱重載)修復崩潰並繼續從應用程式停止的地方進行調試創建美觀,高度定製的用戶體驗受益於使用Flutter框架提供的豐富的Material Design和Cupertino(iOS風格)的widget實現定製、美觀、品牌驅動的設計,而不受原生控制項的限制
Flutter分層架構
Flutter包括一個現代的響應式框架、一個2D渲染引擎、現成的widget和開發工具。這些組件可以幫助您快速地設計、構建、測試和調試應用程式。
Flutter組件一切皆是Widget
Widget是Flutter應用程式用戶界面的基本構建塊。每個Widget都是用戶界面一部分的不可變聲明。 與其他將視圖、控制器、布局和其他屬性分離的框架不同,Flutter具有一致的統一對象模型:widget。
2.計數器應用示例
創建Flutter工程的方法創建一個新的Flutter工程,命名為"yzjflutter"。創建好後,就會得到一個計數器應用的Demo。
詳細源碼
import'package:flutter/material.dart'; // 1.引入material庫// 2.Flutter的入口函數main,裡面調用runApp(MyApp())voidmain()=> runApp(MyApp());// 3. MyApp 繼承StatelessWidget無狀態的widgetclassMyAppextendsStatelessWidget{// This widget is the root of your application. 應用進程的入口@overrideWidget build(BuildContext context){return MaterialApp(title: 'Flutter Demo', // 設置title theme: ThemeData( // 設置theme// This is the theme of your application.//// Try running your application with "flutter run". You'll see the// application has a blue toolbar. Then, without quitting the app, try// changing the primarySwatch below to Colors.green and then invoke// "hot reload" (press "r" in the console where you ran "flutter run",// or simply save your changes to "hot reload" in a Flutter IDE).// Notice that the counter didn't reset back to zero; the application// is not restarted. primarySwatch: Colors.blue, // 狀態欄顏色 ),// 設置入口home為MyHomePage home: MyHomePage(title: 'Flutter Demo Home Page'), ); }}// MyHomePage繼承 StatefulWidget有狀態的WidgetclassMyHomePageextendsStatefulWidget{ MyHomePage({Key key, this.title}) : super(key: key);// This widget is the home page of your application. It is stateful, meaning// that it has a State object (defined below) that contains fields that affect// how it looks.// This class is the configuration for the state. It holds the values (in this// case the title) provided by the parent (in this case the App widget) and// used by the build method of the State. Fields in a Widget subclass are// always marked "final".final String title;// 重寫createState方法返回_MyHomePageState狀態@override_MyHomePageState createState()=> _MyHomePageState(); }class_MyHomePageStateextendsState<MyHomePage> {int _counter = 0; // 點擊次數_counter私有// 看注釋講的很明白:狀態改變了,需要更新狀態及UIvoid_incrementCounter(){ setState(() {// This call to setState tells the Flutter framework that something has// changed in this State, which causes it to rerun the build method below// so that the display can reflect the updated values. If we changed// _counter without calling setState(), then the build method would not be// called again, and so nothing would appear to happen. _counter++; }); }// 實現build構建過程:@overrideWidget build(BuildContext context){// This method is rerun every time setState is called, for instance as done// by the _incrementCounter method above.//// The Flutter framework has been optimized to make rerunning build methods// fast, so that you can just rebuild anything that needs updating rather// than having to individually change instances of widgets.return Scaffold( // Scaffold 是Material庫中提供的頁面腳手架 appBar: AppBar(// Here we take the value from the MyHomePage object that was created by// the App.build method, and use it to set our appbar title. title: Text(widget.title), ), body: Center(// Center is a layout widget. It takes a single child and positions it// in the middle of the parent. child: Column(// Column is also layout widget. It takes a list of children and// arranges them vertically. By default, it sizes itself to fit its// children horizontally, and tries to be as tall as its parent.//// Invoke "debug painting" (press "p" in the console, choose the// "Toggle Debug Paint" action from the Flutter Inspector in Android// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)// to see the wireframe for each widget.//// Column has various properties to control how it sizes itself and// how it positions its children. Here we use mainAxisAlignment to// center the children vertically; the main axis here is the vertical// axis because Columns are vertical (the cross axis would be// horizontal). mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('Hello,World', style: new TextStyle(fontSize: 14)), Text('You have pushed the button this many times:', ), Text('$_counter', style: Theme.of(context).textTheme.display1, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, // 點擊事件onPressed tooltip: 'Increment', child: Icon(Icons.add), ), // This trailing comma makes auto-formatting nicer for build methods. ); }}
MyApp類代表Flutter應用,它繼承了StatelessWidget類,這也就意味著應用本身也是一個widget。在Flutter中,大多數東西都是widget,包括對齊(alignment)、填充(padding)和布局(layout)。Flutter在構建頁面時,會調用組件的build方法,widget的主要工作是提供一個build()方法來描述如何構建UI界面(通常是通過組合、拼裝其它基礎widget)。MaterialApp是Material庫中提供的Flutter APP框架,通過它可以設置應用的名稱、主題、語言、首頁及路由列表等。MaterialApp也是一個widget。Scaffold是Material庫中提供的頁面腳手架,它包含導航欄和Body以及FloatingActionButton(如果需要的話)。 本書後面示例中,路由默認都是通過Scaffold創建。home為Flutter應用的首頁,它也是一個widget。_MyHomePageState的build過程:Flutter框架會調用Widget的build方法來構建widget樹,最終將widget樹渲染到設備屏幕上。
Scaffold是Material庫中提供的一個widget, 它提供了默認的導航欄、標題和包含主屏幕widget樹的body屬性。widget樹可以很複雜。body的widget樹中包含了一個Center widget,Center可以將其子widget樹對齊到屏幕中心,Center子widget是一個Column widget,Column的作用是將其所有子widget沿屏幕垂直方向依次排列, 此例中Column包含兩個Text子widget,第一個Text widget顯示固定文本 「You have pushed the button this many times:」,第二個Text widget顯示_counter狀態的數值。floatingActionButton是頁面右下角的帶「」的懸浮按鈕,它的onPressed屬性接受一個回調函數,代表它被點擊後的處理器,本例中直接將_incrementCounter作為其處理函數。現在,我們將整個流程串起來:當右下角的floatingActionButton按鈕被點擊之後,會調用_incrementCounter,在_incrementCounter中,首先會自增_counter計數器(狀態),然後setState會通知Flutter框架狀態發生變化,接著,Flutter會調用build方法以新的狀態重新構建UI,最終顯示在設備屏幕上。
為什麼要將build方法放在State中,而不是放在StatefulWidget中?
這主要是為了開發的靈活性。如果將build()方法在StatefulWidget中則會有兩個問題:
狀態訪問不便繼承StatefulWidget不便