Flutter布局基础——Stack层叠布局

层叠布局适用于子视图叠放一起,且位置能够相对于父视图边界确认的情况。
比如,可用于图片上加文字,按钮上加渐变阴影等等。

Stack Widget的子视图要么是positioned,要么是non-positionedPositioned子视图是指使用Positioned的widget包括起来的子视图,通过设置相对于Stacktopbottomleftright属性来确认自身位置,其中至少要有一个不为空。

Stack Widget的大小取决于所有non-positioned的子视图。non-positioned的子视图的位置根据alignment属性确定,(当alignmentleft-to-right时,子视图默认从左上角开始;当aligmentright-to-left时,子视图从右上角开始;)。

Stack 基础使用

Stack常用属性

  • Stack常用属性
    • children:子视图
    • alignment:子视图的对齐方式
      • topLeft:顶部左对齐
      • topCenter:顶部居中对齐
      • topRight:顶部右对齐
      • centerLeft:中间左对齐
      • center:中间对齐
      • centerRight:中间右对齐
      • bottomLeft:底部左对齐
      • bottomCenter:底部居中对齐
      • bottomRight:底部右对齐
    • clipBehavior,裁剪,可能会影响性能
      • Clip.hardEdge: Stack默认为此选项
      • Clip.antiAlias: 平滑裁剪
      • Clip.antiAliasWithSaveLayer
      • Clip.none: 不需要裁剪
    • fit:子视图填充方式
      • StackFit.loose: 使用子组件的大小
      • StackFit.expand: 充满父视图的区域
      • StackFit.passthrough: 透传,使用Stack的父视图的布局方式
    • textDirection
      • TextDirection.ltr
      • TextDirection.rtl

Positioned常用属性如下:

  • Positioned常用属性
    • child
    • height
    • width
    • bottom
    • left
    • right
    • top

alignment对齐

使用代码如下:

  1. class MyApp extends StatelessWidget {
  2. @override
  3. Widget build(BuildContext context) {
  4. var stack = new Stack(
  5. alignment: Alignment.bottomRight,
  6. children: [
  7. new Container(
  8. width: 300.0,
  9. height: 300.0,
  10. color: Colors.orange,
  11. ),
  12. new Container(
  13. width: 200.0,
  14. height: 200.0,
  15. color: Colors.green,
  16. ),
  17. new Text(
  18. 'alignment bottomRight',
  19. style: TextStyle(color: Colors.white, fontSize: 21),
  20. )
  21. ],
  22. );
  23. return MaterialApp(
  24. title: 'StackView Widget',
  25. home: Scaffold(
  26. appBar: new AppBar(
  27. title: new Text('StackView Widget'),
  28. ),
  29. body: Center(
  30. child: stack,
  31. ),
  32. ),
  33. );
  34. }
  35. }

效果如下:
Flutter布局基础——Stack层叠布局 - 图1Flutter布局基础——Stack层叠布局 - 图2Flutter布局基础——Stack层叠布局 - 图3
从上面的对比,可以看出alignment的属性,对设置Stack的子视图的效果

clipBehavior属性

为了方便查看clipBehavior的效果,需要写一个相对于Stack超出的子视图,使用Postitioned Widget,设置top、left为负值即可。

代码如下:

  1. class MyApp extends StatelessWidget {
  2. @override
  3. Widget build(BuildContext context) {
  4. var stack = new Stack(
  5. clipBehavior: Clip.antiAliasWithSaveLayer,
  6. children: [
  7. new Container(
  8. width: 300.0,
  9. height: 300.0,
  10. color: Colors.orange,
  11. ),
  12. Positioned(
  13. child: new Container(
  14. width: 200.0,
  15. height: 200.0,
  16. color: Colors.green,
  17. ),
  18. left: -20,
  19. top: -20),
  20. new Text(
  21. 'clip antiAliasWithSaveLayer',
  22. style: TextStyle(color: Colors.white, fontSize: 21),
  23. ),
  24. ],
  25. );
  26. return MaterialApp(
  27. title: 'StackView Widget',
  28. home: Scaffold(
  29. appBar: new AppBar(
  30. title: new Text('StackView Widget'),
  31. ),
  32. body: Center(
  33. child: stack,
  34. ),
  35. ),
  36. );
  37. }
  38. }

效果如下:
Flutter布局基础——Stack层叠布局 - 图4Flutter布局基础——Stack层叠布局 - 图5
从上面可以看出clipBehavior的效果

fit属性

fit填充方式,fit的expand和loose属性很容易区分,但是loose和passthrough属性的区别需要特别注意。为了容易区分出来不同,这里使用Row作为的父视图Stack

简单的理解,expand是充满父视图;loose是按照子视图的大小来;passthrough则是按照父视图的父视图的约束来。

使用代码如下:

  1. class MyApp extends StatelessWidget {
  2. @override
  3. Widget build(BuildContext context) {
  4. var stack = new Stack(
  5. // alignment: Alignment.bottomRight,
  6. fit: StackFit.passthrough,
  7. children: [
  8. new Container(
  9. width: 300.0,
  10. height: 300.0,
  11. color: Colors.orange,
  12. ),
  13. new Container(
  14. width: 200.0,
  15. height: 200.0,
  16. color: Colors.green,
  17. ),
  18. new Text(
  19. 'StackFit passthrough',
  20. style: TextStyle(color: Colors.white, fontSize: 21),
  21. ),
  22. ],
  23. );
  24. return MaterialApp(
  25. title: 'StackView Widget',
  26. home: Scaffold(
  27. appBar: new AppBar(
  28. title: new Text('StackView Widget'),
  29. ),
  30. body: Center(
  31. child: Row(
  32. children: [Expanded(child: stack)],
  33. ),
  34. ),
  35. ),
  36. );
  37. }
  38. }

效果如下:
Flutter布局基础——Stack层叠布局 - 图6Flutter布局基础——Stack层叠布局 - 图7
从上面可以看出,StackFit为passthrough属性时,使用了Row的Expand的布局;StackFit为loose时,使用的是子视图的布局;StackFit为expand时,使用的是Stack的布局。

使用Stack实现渐变背景的效果

代码如下:

  1. class MyApp extends StatelessWidget {
  2. @override
  3. Widget build(BuildContext context) {
  4. var stack = SizedBox(
  5. width: 250,
  6. height: 250,
  7. child: Stack(
  8. children: [
  9. Container(
  10. width: 250,
  11. height: 250,
  12. color: Colors.orange,
  13. ),
  14. Container(
  15. padding: const EdgeInsets.all(5.0),
  16. alignment: Alignment.center,
  17. decoration: BoxDecoration(
  18. gradient: LinearGradient(
  19. colors: [
  20. Colors.black.withAlpha(0),
  21. Colors.black12,
  22. Colors.black45,
  23. ],
  24. begin: Alignment.topCenter,
  25. end: Alignment.bottomCenter,
  26. )),
  27. child: const Text('Foreground Text',
  28. style: TextStyle(color: Colors.white, fontSize: 20.0))),
  29. ],
  30. ),
  31. );
  32. return MaterialApp(
  33. title: 'StackView Widget',
  34. home: Scaffold(
  35. appBar: new AppBar(
  36. title: new Text('StackView Widget'),
  37. ),
  38. body: Center(
  39. child: stack,
  40. ),
  41. ),
  42. );
  43. }
  44. }

效果如下:

Flutter布局基础——Stack层叠布局 - 图8

参考

Stack Dev Doc
Positioned Dev Doc
StackFit Dev Doc
Flutter免费视频第三季-布局