1.Stack
Stack 這個是Flutter中布局用到的組件,可以疊加的現(xiàn)實View.
Stack({
Key key,
this.alignment = AlignmentDirectional.topStart,
this.textDirection,
this.fit = StackFit.loose,
this.overflow = Overflow.clip,
List<Widget> children = const <Widget>[],
})
- alignment : 指的是子Widget的對其方式玫恳,默認情況是以左上角為開始點 薄疚,這個屬性是最難理解的,它區(qū)分為使用了Positioned和未使用Positioned定義兩種情況仍律,沒有使用Positioned情況還是比較好理解的.
- fit :用來決定沒有Positioned方式時候子Widget的大小,StackFit.loose 指的是子Widget 多大就多大,StackFit.expand使子Widget的大小和父組件一樣大.
- overflow :指子Widget 超出Stack時候如何顯示跋炕,默認值是Overflow.clip克锣,子Widget超出Stack會被截斷茵肃,Overflow.visible超出部分還會顯示的.
stack組件的使用
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'title',
home: Scaffold(
appBar: AppBar(title: Text('title'),),
body: Stack(
children: <Widget>[
Container(width: 300,height: 300,color: Colors.cyan,),
Container(width: 200,height: 200,color: Colors.red,),
Container(width: 100,height: 100,color: Colors.yellow,),
],
),
),
);
}
}
fit 屬性使用
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'title',
home: Scaffold(
appBar: AppBar(
title: Text("stack title"),
actions: <Widget>[
RaisedButton(
onPressed: () {
},
color: Colors.blue,
child: Icon(Icons.add),
),
],
),
body: Stack(
fit: StackFit.expand,
children: <Widget>[
Container(
width: 100,
height: 100,
color: Colors.red,
),
Container(
width: 90,
height: 90,
color: Colors.blue,
),
Container(
width: 80,
height: 80,
color: Colors.green,
),
],
),
),
);
}
}
如果指定是StackFit.expand,所以的子組件會和Stack一樣大的.
如果指定是StackFit.loose袭祟,所以子Widget 多大就多大.
2. Position
這個使用控制Widget的位置验残,通過他可以隨意擺放一個組件,有點像絕對布局.
Positioned({
Key key,
this.left,
this.top,
this.right,
this.bottom,
this.width,
this.height,
@required Widget child,
})
left巾乳、top 您没、right、 bottom分別代表離Stack左胆绊、上紊婉、右、底四邊的距離
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'title',
home: Scaffold(
appBar: AppBar(
title: Text("Postion Title"),
),
body: Stack(
children: <Widget>[
Positioned(
top: 100.0,
child: Container(
color: Colors.blue,
child: Text("第一個組件"),
),
),
Positioned(
top: 200,
right: 100,
child: Container(
color: Colors.yellow,
child: Text("第二個組件"),
),
),
Positioned(
left: 100.0,
child: Container(
color: Colors.red,
child: Text("第三個組件"),
),
),
],
),
),
);
}
}
這個地方有注意地方辑舷,例如說第一個組件我指定距離左邊0個距離喻犁,距離右邊0個距離,那么這個組件的寬度就是屏幕這么寬何缓,因為你指定的左右間距都是0肢础,也就是沒有間距.
如果指定了left&&right&&top&bottom都是0的情況,那么這個組件就是和Stack大小一樣填滿它.
3. GridTile
GridTile 是一個Flutter 提供的組件的,用來在GridView中給Item 增加更豐富的展示用的碌廓,GridTile 的布局方式就是Stack传轰,在源代碼中就到Positioned 來進行位置控制,主要提供三個Widget的展示分別為child谷婆、header慨蛙、footer辽聊,我們看一下源代碼:
class GridTile extends StatelessWidget {
/// Creates a grid tile.
///
/// Must have a child. Does not typically have both a header and a footer.
const GridTile({
Key key,
this.header,
this.footer,
@required this.child,
}) : assert(child != null),
super(key: key);
/// The widget to show over the top of this grid tile.
///
/// Typically a [GridTileBar].
final Widget header;
/// The widget to show over the bottom of this grid tile.
///
/// Typically a [GridTileBar].
final Widget footer;
/// The widget that fills the tile.
///
/// {@macro flutter.widgets.child}
final Widget child;
@override
Widget build(BuildContext context) {
if (header == null && footer == null)
return child;
final List<Widget> children = <Widget>[
Positioned.fill(
child: child,
),
];
if (header != null) {
children.add(Positioned(
top: 0.0,
left: 0.0,
right: 0.0,
child: header,
));
}
if (footer != null) {
children.add(Positioned(
left: 0.0,
bottom: 0.0,
right: 0.0,
child: footer,
));
}
return Stack(children: children);
}
}
4. alignment
A.沒有使用postioned定位的情況:
在第一個stack組件的代碼中使用的就是positioned定位的情況,默認的子組件的對齊方式就是以左上角為基準開始排列的,我們再來了解一下其他的對齊方式.
①.AlignmentDirectional.bottomEnd
AlignmentDirectional.bottomEnd的方式是從右下角為基準開始對齊:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'title',
home: Scaffold(
appBar: AppBar(
title: Text("Postion Title"),
),
body: Stack(
// fit: StackFit.expand,
alignment: AlignmentDirectional.bottomEnd,
children: <Widget>[
Container(
width: 100,
height: 100,
color: Colors.red,
),
Container(
width: 90,
height: 90,
color: Colors.blue,
),
Container(
width: 80,
height: 80,
color: Colors.green,
),
]),
),
);
}
}
②.AlignmentDirectional.topEnd
AlignmentDirectional.bottomEnd的方式是從左上角為基準開始對齊:
③.AlignmentDirectional.center
AlignmentDirectional.center的方式是以stack的中心位置:
④.AlignmentDirectional.centerEnd
所有的Widget 在Stack的中心位置并且右邊跟stack右邊挨著
⑤.AlignmentDirectional.centerStart
所有的Widget 在Stack的中心位置并且左邊跟stack左邊挨著
B.使用postioned定位的情況:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'title',
home: Scaffold(
appBar: AppBar(
title: Text("Postion Title"),
),
body: Stack(
// alignment: AlignmentDirectional.bottomEnd,
overflow: Overflow.visible,
children: <Widget>[
Positioned.fill(
child: Container(
color: Colors.black45,
),
),
Positioned(
top: 100.0,
left: 0,
right: 20,
child: Container(
color: Colors.blue,
child: Text("第一個組件"),
),
),
Positioned(
top: 200,
bottom: 20,
child: Container(
color: Colors.yellow,
child: Text("第二個組件"),
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
color: Colors.red,
child: Text("第三個組件"),
),
),
],
),
),
);
}
}
這種情況是alignment 是默認值的效果,下面我們修改一下alignment的對應(yīng)的值.
①.AlignmentDirectional.bottomEnd
bottomEnd是子Widget的底部和Stack底部對齊期贫,并且子Widget的右邊和Stack右邊對齊.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'title',
home: Scaffold(
appBar: AppBar(
title: Text("Postion Title"),
),
body: Stack(
alignment: AlignmentDirectional.bottomEnd,
overflow: Overflow.visible,
children: <Widget>[
Positioned.fill(
child: Container(
color: Colors.black45,
),
),
Positioned(
top: 100.0,
left: 0,
right: 20,
child: Container(
color: Colors.blue,
child: Text("第一個組件"),
),
),
Positioned(
top: 200,
bottom: 20,
child: Container(
color: Colors.yellow,
child: Text("第二個組件"),
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
color: Colors.red,
child: Text("第三個組件"),
),
),
],
),
),
);
}
}
會發(fā)現(xiàn)這個圖的效果和上一個圖的效果唯一區(qū)別就是黃色的第二個組件的位置有變化跟匆,這是為什么呢?
先說第一個組件和第三組件的位置為什么沒有改變:
Positioned(
top: 100.0,
left: 0,
right: 20,
child: Container(
color: Colors.blue,
child: Text("第一個組件"),
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
color: Colors.red,
child: Text("第三個組件"),
),
),
第一個組件top是100通砍,說明這個組件距離頂部的距離是固定的玛臂,雖然Stack的aligment=AlignmentDirectional.bottomEnd,是不生效的封孙,當這兩個屬性沖突時迹冤,以Positioned的距離為主,為什么第一組件右邊也沒有Stack的右邊對齊呢虎忌?因為right=20泡徙,第一個組件右邊距離已經(jīng)可以確認了,所以也不受到aligment=AlignmentDirectional.bottomEnd的影響.
第三個組件也是一樣的膜蠢,第三個組件的寬度是Stack的寬度堪藐,高度取決于Text組件的高度,最關(guān)鍵的是它的bottom=0狡蝶,也就是第三個組件要和Stack組件的低邊界對齊庶橱,所以它的效果和上面的圖是沒有變化的.
Positioned(
top: 200,
bottom: 20,
child: Container(
color: Colors.yellow,
child: Text("第二個組件"),
),
),
第二個組件為什么會跑到右邊呢?
因為第二個組件的高度是可以確認出來的贪惹,top=200苏章,bottom=20,設(shè)置這兩個屬性就能推斷出第二組的高度是多大奏瞬,但是第二個組件的寬度取決于Text("第二個組件") 的寬度枫绅,顯然是水平方向上是不能填滿Stack的,這個時候AlignmentDirectional.bottomEnd屬性起作用了硼端,bottom的距離已經(jīng)確定了并淋,所以底部的對齊方式是不會變化了,但是第二組件右邊的對齊方式是可以收到AlignmentDirectional.bottomEnd影響的珍昨,所以第二組件展示的位置就是圖片上展示的位置.