Container類裏有一個alignment屬性,翻譯過來應該叫對齊方式,這個屬性用來控制Container的子控件相對於它自身的一個位置。在咱們iOS開發中,咱們知道座標系的原點是在左上角。而在flutter中,座標系的原點在父控件的正中心,可使用這個alignment屬性來控制子控件在父控件中的位置,它有兩個參數分別是double類型的x,y。取值是-1到1,當0,0的時候表示子控件在父控件的正中心;當1,0的時候,表示子控件位於x方向上的最右側,y方向上居中;當-1,-1的時候,表示子控件位於父控件的左上角位置。有點相似於CALayer的anchorPoint屬性。如圖代碼以下: 數組
Row表示水平佈局,它有一個children屬性,用來存放它的子控件。代碼以下: 微信
最開始咱們嘗試了alignment屬性的做用,當它是0,0的時候,Text的位置默認是在屏幕中央的。爲何這裏換成咱們的Row以後,Row的子控件位置不在屏幕中央呢?markdown
Row 和 Column 都有一個mainAxisAlignment屬性,叫做主軸對齊方式,默認是MainAxisAlignment.start意思沿着主軸方向開始,Row佈局下就是從左至右,Column佈局下就是從上至下。
MainAxisAlignment.spaceAround
:將剩下的空間平均分配
MainAxisAlignment.spaceBetween
:將剩下的空間分配到子控件之間
MainAxisAlignment.spaceEvenly
:等間距分配子控件框架
交叉軸對齊方式,start,end,center這幾種方式試一下很好理解,stretch會將子控件拉伸。而baseline用的比較少,單獨使用它會報錯,須要和Text文本結合,還須要配合textBaseline
屬性一塊兒使用。以下圖所示,若是不設置CrossAxisAlignment.baseline
和TextBaseline.alphabetic
就會根據控件高度水平對齊,而若是設置了就會根據控件內文本的基線對齊。
less
這個和Row是對應的,Row是水平佈局,這個Column是垂直佈局ide
class LayoutDemo extends StatelessWidget {
const LayoutDemo({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
color: Colors.green,
alignment: Alignment(0, 0),
child: Column(
children: [
Container(
child: Icon(Icons.add, size: 180,),
color: Colors.red,
),
Container(
child: Icon(Icons.ac_unit, size: 120,),
color: Colors.yellow,
),
Container(
child: Icon(Icons.access_alarm, size: 60,),
color: Colors.blue,
),
],
),
);
}
}
複製代碼
顯示效果如圖:佈局
這個跟Row相似動畫
這個跟Row相似ui
這個是用在Z軸上的佈局的,row是X軸,column是Y軸。children數組第一個放在最底部,最後一個放在上面,離用戶最近的地方。spa
class LayoutDemo extends StatelessWidget {
const LayoutDemo({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
color: Colors.green,
alignment: Alignment(0, 0),
child: Stack(
children: [
Container(
child: Icon(Icons.add, size: 180,),
color: Colors.red,
),
Container(
child: Icon(Icons.ac_unit, size: 120,),
color: Colors.yellow,
),
Container(
child: Icon(Icons.access_alarm, size: 60,),
color: Colors.blue,
),
],
),
);
}
}
複製代碼
APP顯示效果:
Stack裏有一個alignment屬性,它用來控制全部子控件相對於最大那個子控件的位置
class StackDemo extends StatelessWidget {
const StackDemo({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.bottomRight,
children: [
Container(
child: Icon(Icons.add, size: 180,),
color: Colors.red,
),
Container(
child: Icon(Icons.ac_unit, size: 120,),
color: Colors.yellow,
),
Container(
child: Icon(Icons.access_alarm, size: 60,),
color: Colors.blue,
),
],
);
}
}
複製代碼
Stack裏配合Positioned類使用的話,跟咱們iOS的約束有點相似了,能夠設置上,左間距之類的
class StackDemo extends StatelessWidget {
const StackDemo({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Stack(
children: [
Positioned(
child: Container(
child: Icon(
Icons.add,
size: 180,
),
color: Colors.red,
),
),
Positioned(
child: Container(
child: Icon(
Icons.ac_unit,
size: 120,
),
color: Colors.yellow,
),
),
Positioned(
top: 20,
left: 20,
right: 20,
child: Container(
child: Icon(
Icons.access_alarm,
size: 60,
),
color: Colors.blue,
),
),
],
);
}
}
複製代碼
Expanded是一個相似Container的經常使用的佈局容器,它用來填充佈局,使用了填充佈局在主軸方向上是不會有間隔的,因此Expanded用在Row裏面的時候,子控件的寬度設置就沒有意義了,而在Column裏面使用的使用,子控件的高度設置就沒有意義了。這裏以Column爲例:
class LayoutDemo extends StatelessWidget {
const LayoutDemo({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
color: Colors.green,
alignment: Alignment(0, 0),
child: Column(
children: [
Expanded(
child: Container(
child: Icon(Icons.add, size: 180,),
color: Colors.red,
),
),
Expanded(
child: Container(
child: Icon(Icons.ac_unit, size: 120,),
color: Colors.yellow,
),
),
Expanded(
child: Container(
child: Icon(Icons.access_alarm, size: 60,),
color: Colors.blue,
),
),
],
),
);
}
}
複製代碼
AspectRatio是一個容器類,它有一個屬性aspectRatio表示寬高比。若是指定了寬度,根據這個aspectRatio能夠自動算出高度;若是指定了高度,根據aspectRatio能夠自動算出寬度。以下面代碼指定了父視圖高度爲100,aspectRatio寬高比爲2,子視圖寬度就是200,再把父視圖撐起來也是200。
class LayoutDemo extends StatelessWidget {
const LayoutDemo({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
color: Colors.green,
alignment: Alignment(0, 0),
child: Container(
color: Colors.blue,
height: 100,
child: AspectRatio(
aspectRatio: 2,
child: Icon(
Icons.add,
),
),
));
}
}
複製代碼
以前介紹的這麼多類都是無狀態的,意思是顯示以後沒辦法更新UI的,若是想要實時更新UI的話,就不能繼承無狀態的類了。咱們先來看一個例子:明明count變化了,可是界面顯示沒有變化 記得修改APP的home視圖
而後點擊屏幕右下角的加號按鈕,能夠發現明明控制檯打印了count的值已經發生了變化,可是界面顯示依然是0
下面咱們解決這個問題,將StateManagerDemo繼承改成StatefulWidget,實現createState方法返回一個自定義的State對象,自定義的State對象裏面實現build方法。還須要注意在按鈕的點擊方法裏調用一下setState方法。這樣每次點擊加號按鈕就能實時更新UI了。改造完以後以下圖所示:
到目前爲止,咱們對flutter的一些基礎知識就算是介紹的差很少了。接下來咱們開始作一個簡單的仿微信APP。咱們應該都有經驗,理論的知識學得再多,不動手開始敲代碼,不在項目中運用,是很難真正掌握一門知識的。
新建一個flutter工程,命名wechat_demo:
刪掉多餘的代碼,能夠所有從新本身寫:
建立底部的TabBar和item,默認的type是白色的,顯示效果很難看因此改成fixed,還能夠設置fixedColor:
BottomNavigationBar有一個屬性currentIndex即表明了當前選中的下標。咱們能夠經過設置它的值來控制哪一個按鈕被選中。既然須要改變UI了,說明咱們須要將StatelessWidget改成StatefulWidget了。還有一個參數onTap是用來回調點擊事件的。實現點擊事件,切換currentIndex,從新setState就能夠實現,點擊切換了。咱們將bottomNavigationBar相關代碼放到一個新的文件rootPage中。代碼以下: 記得修改main.dart文件中
這樣就實現了APP的底部TabBar的展現,點擊功能。點擊每一個item的時候,會發現flutter的bottomNavigationBar還自帶了動畫效果...
咱們知道Scaffold還有一個body的屬性,表示展現在屏幕上的內容。咱們每一個item對應的界面都須要一個AppBar,那麼也許意味着,body屬性還須要一個Scaffold來展現咱們的每一個item對應的內容。 能夠看到微信首頁就已經大概出來了,可是點擊的時候只會顯示這個微信頁面,怎麼實現切換不一樣的頁面呢,確定須要一個數組,來存放對應的每一個頁面了。
而後body裏,根據咱們的_currentIndex返回對應的body 這樣點擊每一個item都會跳轉到對應的界面了,APP的主框架的搭建好了。
今天主要講了flutter的三大布局類Row,Column,Stack以及他們的一些屬性。而後是有狀態的Widget和無狀態的Widget,最後搭建了一下咱們要作的仿微信APP的底部bottomNavigationBar和切換頁面功能