前面幾期的專欄對你們來講學習起來還算輕鬆加愉快,咱們簡單認識了flutter這門新技術,而且嘗試着學習了像Text、Image、TextField幾個簡單的Widget,而且咱們用這幾個Widget作了一些簡單的交互,好像咱們並無注重Widget的顯示位置跟排版,咱們只是讓他顯示出來而已,而後要想把這些Widget組合起來放在一個渲染到整個手機屏幕上,咱們須要合理的選用一個容器來包裹這些Widget,或者說讓這些Widget溫馨的排列在一個恰當的容器裏,就像咱們在作原生android時,若是UI上須要繪製一個水平或者豎直的view排列,咱們會選用LinearLayout而不會去選FrameLayout,同理在Flutter上佈局的排放咱們也要適當的選擇正確的容器。前端
在Flutter中也給咱們提供了各類不一樣應用場景的layout,咱們能夠根據UI上排版的須要來選用不一樣的layout去完成咱們對UI的繪製,在這些layout中,有些layout的借鑑了前端的盒子佈局模型,有些徹底跟原生android思想一致,因此對於咱們來講學習起來並無那麼抽象,下面我列出幾個經常使用的layout,而且舉例跟你們一塊看看Flutter究竟是怎麼完成Widget的佈局的。android
這兩種佈局方式幾乎同樣,因此我把它倆放在一塊講解,先看下源碼對兩者的描述bash
class Column extends Flex {
/// Creates a vertical array of children.
class Row extends Flex {
/// Creates a horizontal array of children.
複製代碼
從源碼註釋中咱們瞭解到兩者都是一個盛放children widget的array,不一樣的是一個是在水平方向(horizontal),另外一個是豎直方向(vertical)app
因爲兩者相似,咱們只拿Row作講解,來一塊分析下Row構造方法,看下提供給咱們可定製的屬性有哪些less
Row({
Key key,
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
MainAxisSize mainAxisSize = MainAxisSize.max,
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
TextDirection textDirection,
VerticalDirection verticalDirection = VerticalDirection.down,
TextBaseline textBaseline,
List<Widget> children = const <Widget>[],
})
複製代碼
主軸方向上的對齊方式,會對child的位置起做用,默認是start。其中MainAxisAlignment枚舉值:ide
在主軸方向佔有空間的值,默認是max。MainAxisSize的取值有兩種:佈局
children在交叉軸方向的對齊方式,與MainAxisAlignment略有不一樣。CrossAxisAlignment枚舉值有以下幾種:學習
阿拉伯語系的兼容設置,通常無需處理。測試
定義了children擺放順序,默認是down。VerticalDirection枚舉值有兩種:ui
使用的TextBaseline的方式,有兩種,前面已經介紹過。
乾巴巴的說了這麼多確實有點枯燥,上個圖直觀感覺一下Row,我在Row裏面水平排列了幾個RaisedButton
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(home: new LayoutDemo()));
}
class LayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("水平方向佈局"),
),
//佈局方向 Row:水平佈局 Column:垂直佈局
body: new Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
new RaisedButton(
onPressed: () {
print('點擊紅色按鈕');
},
color: const Color(0xffff0000),
child: new Text('紅色按鈕'),
),
new RaisedButton(
onPressed: () {
print("點擊藍色按鈕");
},
color: const Color(0xff000099),
child: new Text('藍色按鈕'),
),
new RaisedButton(
onPressed: () {
print("點擊粉色按鈕");
},
color: const Color(0xffee9999),
child: new Text('粉色按鈕'),
)
],
),
);
;
}
}
複製代碼
cloumn與Row大同小異,讀者可自行測試,我就不詳細貼代碼演示了。下面咱們一塊來看另一種layout方式。
Stack即層疊佈局,跟原生Android裏面的FrameLayout一模一樣,可以將子widget層疊排列。若是不指定顯示位置,默認佈局在左上角,若是但願子空間顯示在具體的位置,咱們能夠經過Positioned控件包裹子widget,而後根據定位的子控件的top、right、bottom、left屬性來將它們放置在Stack的合適位置上。
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(home: new StackLayoutDemo()));
}
class StackLayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('層疊佈局'),
),
body: new Center(
child: new Stack(
children: <Widget>[
new Image.network(
'https://avatar.csdn.net/6/0/6/1_xieluoxixi.jpg',
scale: 0.5,
),
new Positioned(
left: 35.0,
right: 35.0,
top: 45.0,
child: new Text(
'第二層內容區域',
style: new TextStyle(
fontSize: 20.0,
fontFamily: 'serif',
),
)),
new Positioned(
left: 55.0,
right: 55.0,
top: 55.0,
child: new Text(
'第三層 this is the third child',
style: new TextStyle(
fontSize: 20.0,
color: Colors.blue,
fontFamily: 'serif',
),
))
],
),
));
}
}
複製代碼
Center佈局使用比較簡單,場景也比較單一,通常用於協助其餘子widget佈局,包裹其child widget顯示在上層佈局的中心位置。上述Stack佈局中就利用Center讓其顯示在屏幕正中心,看下官方對Center的解釋:
class Center extends Align {
/// Creates a widget that centers its child.
const Center({ Key key, double widthFactor, double heightFactor, Widget child })
: super(key: key, widthFactor: widthFactor, heightFactor: heightFactor, child: child);
}
複製代碼
比較簡單直接,我就不貼效果圖了,讀者可自行利用center包裹子widget作測試,從而直觀體驗一下center佈局。
//Center既中心定位控件,可以將子控件放在其內部中心。
class CenterLayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('中心佈局'),
),
body: new Center(
child: new Text('我在屏幕中央'),
),
);
}
}
複製代碼
Listview使用場景跟原生Android同樣,都是用於展現長列表數據,也是咱們開發中使用的比較多的widget之一,本章節主要分析layout,就不詳細展開分析,帶你們簡單認識下ListView的用法,後續咱們專門抽出一個章節講解ListView,跟listView相似的還有GridView。
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(home: new ListViewLayoutDemo()));
}
class ListViewLayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('滾動佈局'),
),
body: new ListView(
children: <Widget>[
new Center(
child: new Text(
'\n大標題',
style: new TextStyle(fontFamily: 'serif', fontSize: 20.0),
),
),
new Center(
child: new Text(
'小標題',
style: new TextStyle(
fontFamily: 'serif',
fontSize: 12.0,
),
),
),
new Center(
child: new Text(
''' 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 內容sadf手動閥防守打法 發生富士達發生發生飛都是 ''',
style: new TextStyle(fontSize: 14.0),
),
)
],
),
);
}
}
複製代碼
Align即對齊控件,能將子控件按照所指定的方式對齊,並根據子控件的大小調整本身的大小。Align對齊子控件的方式有以下幾種
bottomCenter (0.5, 1.0) 底部中心
bottomLeft (0.0, 1.0) 左下角
bottomRight (1.0, 1.0) 右下角
center (0.5, 0.5) 水平垂直居中
centerLeft (0.0, 0.5) 左邊緣中心
centerRight (1.0, 0.5) 右邊緣中心
topCenter (0.5, 0.0) 頂部中心
topLeft (0.0, 0.0) 左上角
topRight (1.0, 0.0) 右上角
複製代碼
來簡單使用一下:
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(home: new AlignLayoutDemo()));
}
class AlignLayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Align佈局'),
),
body: new Stack(
children: <Widget>[
new Align(
alignment: new FractionalOffset(0.0, 0.5),
child: new Text(
'我在左邊緣中心',
style: new TextStyle(fontSize: 35.0),
),
),
new Align(
alignment: new FractionalOffset(1.0, 1.0),
child: new Text(
'我在右下角',
style: new TextStyle(fontSize: 30.0),
),
)
],
),
);
}
}
複製代碼
SizedBox可以強制控制子控件的寬高顯示,好比我指定一個寬高都爲200的SiezedBox佈局,其裏面的child widget的寬高也就被限定死了最大寬高爲SizedBox的寬高,即便他有更大的寬高。
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(home: new SizedBoxLayoutDemo()));
}
class SizedBoxLayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('SizedBox佈局'),
),
body: new SizedBox(
width: 200.0,
height: 200.0,
child: new Container(
decoration: new BoxDecoration(color: Colors.red),
),
),
);
}
}
複製代碼
利用SizedBox限定Container的寬高爲200:
Opacity控件能調整子控件的不透明度,使子控件部分透明,不透明度的量從0.0到1.1之間,0.0表示徹底透明,1.1表示徹底不透明。
如圖:我在StackLayout中放置兩個子widget,其中Text在Stack下方,我把上層Opacity佈局的透明度設置爲0.5,咱們能夠隱約看見下層Text顯示的內容,讀者可自行把透明度更改值測試結果。
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(home: new OpacityLayoutDemo()));
}
//Opacity控件能調整子控件的不透明度,使子控件部分透明,不透明度的量從0.0到1.1之間,0.0表示徹底透明,1.1表示徹底不透明。
class OpacityLayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.white,
appBar: new AppBar(
title: new Text('Opacity'),
),
body: new Center(
child: new Stack(
alignment: AlignmentDirectional.center,
children: <Widget>[
new Text("我在透明區域下方"),
new Opacity(
opacity: 0.5,
child: new Container(
width: 200.0,
height: 220.0,
decoration: new BoxDecoration(color: Colors.redAccent),
),
),
],
),
),
);
}
}
複製代碼