1.Widge組件分類
在flutter中,所有UI元素都是widget組件,除了我們常見的button,Image這些可見元素,布局也是組件,甚至文本格式控制也是組件。這里我們先簡單講解一下我們通常概念的上的UI控件。在flutter中組件有兩種:有狀態(tài)組件和無狀態(tài)組件。
- 無狀態(tài)組件(stateless widget),無狀態(tài)組件不提供可變狀態(tài)維護(hù),無狀態(tài)組件僅根據(jù)其屬性來渲染,
- 有狀態(tài)組件(stateful Widget),組件自己維護(hù)狀態(tài),組件渲染由SetState方法調(diào)用,更具state的變化差異來更新渲染。所有的stateful widget都是建立在stateless widget上的。
這里我們先講解stateless widget, flutter中的stateless widget主要分為這幾類: - Visual Base Elemet, 可視基礎(chǔ)元素比如:Text,Image, Icon
- Layout: 布局元素,flutter比較特別一點(diǎn),它把布局也作為頁面元素,這樣做的主要目的是可以簡化布局計(jì)算。以前UI做Layout通常通過Layout引擎根據(jù)預(yù)定的約束來進(jìn)行計(jì)算, 計(jì)算過程實(shí)際上是做多元方程式求解,元素越多求解計(jì)算就越慢,參考:從 Auto Layout 的布局算法談性能
。而flutter將layout也作為頁面元素,使得布局在局部范圍就可以求解。Layout元素有:Row,Column,Center,Align,Padding等 -
Painting and Effect Widgets& Animation and Motion
,繪制和效果組件。繪制和效果組件主要是負(fù)責(zé)可視元素的裝飾效果,比如實(shí)現(xiàn)邊框(DecoratedBox),實(shí)現(xiàn)半透明(Opacity),位移旋轉(zhuǎn)變換(Transform),Animation and Motion是比較特殊的效果組件,用于實(shí)現(xiàn)動(dòng)畫效果 - Container&compound element 大多數(shù)我們常用的各種控件都是由基礎(chǔ)元素和布局組合而成的,比如button由Text,Image,DecoratedBox等元素組成
- Interaction Model Widgets, 這個(gè)是專門處理事件響應(yīng)的組件,用于響應(yīng)用戶的操作
2.讓我們來創(chuàng)建Hello World
首先我們先來寫一個(gè)最基本的flutter應(yīng)用吧。
1.在適當(dāng)?shù)哪夸泩?zhí)行:
flutter init -o my_hello_world_app
2.替換my_hello_world_app/lib/main.dart文件中的內(nèi)容:
import 'package:flutter/material.dart';
void main() => runApp(new Center(child: new Text('Hello, world!')));
3.在my_hello_world_app目錄下執(zhí)行:
flutter start
4.你將會(huì)在手機(jī)上看到:
如果你能一切順利的來到這里,那么恭喜你,你已經(jīng)成功使用flutter開發(fā)了一個(gè)android的應(yīng)用,雖然這個(gè)應(yīng)用看上去比較單一。
main方法是這個(gè)應(yīng)用的入口,要運(yùn)行一個(gè)應(yīng)用的話需要使用runApp方法,它接收一個(gè)Widget控件作為參數(shù),并且把這個(gè)控件作為控件樹的根節(jié)點(diǎn)。在我們這個(gè)例子里,控件樹里有兩個(gè)控件,Center
控件和它的子節(jié)點(diǎn)Text
。通常情況下框架會(huì)強(qiáng)制將根控件充滿整個(gè)屏幕,所以相對的Text控件就以屏幕為中心了。
重要概念:
在編寫flutter應(yīng)用的時(shí)候,通常情況下需要自定義組件,這些組件繼承自StatelessComponent
或StatefulComponent
,選擇要繼承哪一個(gè)取決于這個(gè)組件是否需要管理狀態(tài)和配置。一個(gè)組件的主要工作就是實(shí)現(xiàn)build
方法,這個(gè)方法用來反應(yīng)該組件在其他組件中的表現(xiàn)形式。最后底層框架會(huì)統(tǒng)一從上到下調(diào)用build方法直至渲染樹的最底層。
基本控件
flutter提供了一套完備的基本控件,最常用的有如下幾個(gè):
- Text :Text提供了一個(gè)用來顯示文本的一次性控件(即無狀態(tài))。
- Row, Column:這兩個(gè)控件用來顯示水平或垂直方向上的多個(gè)組件,并且是可伸縮的。
- Stack:可以將多個(gè)組件以一定的順序排列,可以使用
Positioned
控件來指定組件在Stack中的順序。 - Container: 是一個(gè)可視化的矩形控件,它可以使用
BoxDecoration
來進(jìn)行外觀裝飾,裝飾內(nèi)容可以是背景,邊框和陰影等。Container也有外邊距,內(nèi)邊距等屬性,也可以約束自身的大小,另外值得一提的是Container還可以利用矩陣在三維控件內(nèi)做轉(zhuǎn)換。
下面結(jié)合一些基本的控件來自定義我們的組件并構(gòu)建應(yīng)用:
修改main.dart代碼如下
import 'package:flutter/material.dart';
class MyToolBar extends StatelessComponent { //(3)
MyToolBar({ this.title });
final Widget title; //(6)
Widget build(BuildContext context) {
return new Container(
height: 56.0,
padding: const EdgeDims.symmetric(horizontal: 8.0),
decoration: new BoxDecoration(
backgroundColor: Colors.blue[500]
),
child: new Row([
new IconButton(icon: 'navigation/menu'),
new Flexible(child: title),
new IconButton(icon: 'action/search'),
])
);
}
}
class MyScaffold extends StatelessComponent { //(4)
Widget build(BuildContext context) {
return new Material(
child: new Column([
new MyToolBar(
title: new Text('Example title', style: Typography.white.title)
),
new Flexible(
child: new Center(
child: new Text('Hello, world!')
)
)
])
);
}
}
void main() {
runApp(new MaterialApp( //(1)
title: 'My app',
routes: <String, RouteBuilder>{ //(2)
'/': (RouteArguments args) => new MyScaffold() //(5)
}
));
}
同時(shí)確保flutter.yaml
文件內(nèi)容如下:
name: my_app
material-design-icons:
- name: action/search
- name: navigation/menu
我們先來運(yùn)行一下這個(gè)應(yīng)用:
恭喜你,順利存活。
代碼解釋如下:
- (1)處的
MaterialApp
是整個(gè)應(yīng)用的主題控件,一般我們自定義的組件要寫在它里面才會(huì)有Material的主題風(fēng)格 - (2)處的
routes
的作用是頁面導(dǎo)航作用,/
表示應(yīng)用打開的第一個(gè)頁面。 - (3)處的
MyToolBar
是我們自定義的一個(gè)無狀態(tài)組件,通過build方法,我們可以看出其最外層是一個(gè)Container
控件,控件高為56dp,左右內(nèi)邊距8dp,它由一個(gè)BoxDecoration
做修飾,修飾內(nèi)容是將背景顏色改為Colors.blue[500]
這種顏色。Container的內(nèi)部是一個(gè)Row
,Row的兩端分別是一個(gè)圖標(biāo)按鈕,中間是另一個(gè)控件Flexible
,它的作用是填充掉Row的剩余部分。在Flexible中傳入的是title
這個(gè)內(nèi)部字段。 - (4)處的
MyScaffold
組件將其子節(jié)點(diǎn)用垂直的方式組織起來,在Column
的第一個(gè)位置是我們自定義的MyToolBar
,在構(gòu)造MyToolBar的時(shí)候?qū)⒁粋€(gè)Text
控件作為它的命名可選參數(shù)title的值傳遞進(jìn)去。在Column的第二個(gè)位置是一個(gè)Flexible
用來填充剩余的空間,在Flexible里面放置了一個(gè)Center
組件,Center組件里則是一個(gè)Text用來顯示“Hello,World”。 - (5)處表示這個(gè)應(yīng)用的第一個(gè)見面就是
MyScaffold
。
這種flutter這種層層包裹的感覺就是前面提到的組件外構(gòu)建UI一小部分含義,眼尖的同學(xué)可能已經(jīng)看到(6)處的title使用的是final修飾符,這里要說明一下繼承自StatelessComponent的組件,如內(nèi)部有配置,屬性或狀態(tài)的統(tǒng)一需要使用final修飾符,表示這個(gè)組件本身自己是無狀態(tài)的,需要依賴它外部的其他組件。這也是'組件外構(gòu)建UI'最重要的含義所在。
Material應(yīng)用
上面那個(gè)應(yīng)用我們使用自己的組件進(jìn)行應(yīng)用開發(fā),發(fā)現(xiàn)應(yīng)用整體美觀度不高。是因?yàn)閒lutter中應(yīng)用界面會(huì)撐滿整個(gè)屏幕,所以有一部分內(nèi)容可能會(huì)被狀態(tài)欄擋住。其實(shí)flutter提供了一系列的控件供開發(fā)人員開發(fā)Material風(fēng)格的應(yīng)用,這之中就有MaterialApp
,Scaffold
,ToolBar
和FloatingActionButton
等。下面看一個(gè)使用了這些控件的例子:
修改main.dart內(nèi)容如下:
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
title: 'Flutter Tutorial',
routes: {'/': (RouteArguments args) => new TutorialHome()}));
}
class TutorialHome extends StatelessComponent {
Widget build(BuildContext context) {
return new Scaffold(
toolBar: new ToolBar(
left: new IconButton(icon: 'navigation/menu'),
center: new Text('Example title'),
right: [new IconButton(icon: 'action/search')]),
body: new Center(child: new Text('Hello, world!')),
floatingActionButton:
new FloatingActionButton(child: new Icon(icon: 'content/add')));
}
}
修改flutter.yaml
文件內(nèi)容如下:
name: my_app
material-design-icons:
- name: action/search
- name: content/add
- name: navigation/menu
運(yùn)行結(jié)果如下:
現(xiàn)在我們的應(yīng)用看起來是不是更像是一個(gè)Material Design
的應(yīng)用了?我們使用的Scaffold
和ToolBar
讓ToolBar自帶了陰影并且字體風(fēng)格有有了調(diào)整。另外還加上了FloatingActionButton
。
總結(jié)
本文主要講解flutter中的組件分類,對如何創(chuàng)建簡單Stateless組件進(jìn)行了演示