在 stack 中 可以使用 Positioned定位。

Stack 基本用法。

  1. Stack(
  2. fit : StackFit.loose,
  3. children : <Widget>[
  4. Container(
  5. width : 200,
  6. height : 200,
  7. color: Colors.red,
  8. ),
  9. Container(
  10. width : 180,
  11. height : 180,
  12. color: Colors.blue,
  13. ),
  14. Container(
  15. width : 160,
  16. height : 160,
  17. color: Colors.green,
  18. ),
  19. Container(
  20. width : 140,
  21. height : 140,
  22. color: Colors.yellow,
  23. ),
  24. ]
  25. )

WechatIMG72.png

Stack的基本属性都有

  1. Stack({
  2. Key key,
  3. this.alignment = AlignmentDirectional.topStart,
  4. this.textDirection,
  5. this.fit = StackFit.loose,
  6. this.overflow = Overflow.clip,
  7. List<Widget> children = const <Widget>[],
  8. }) : super(key: key, children: children);
  • alignment : 指的是子Widget的对齐方式,默认对齐方式为左上角Alignment.topLeft。这个属性 使用Positioned 和 未使用 Positioned 是有些区别的。
  • fit : 用来决定没有使用Positioned方式时候Widget的大小,StackFit.loose是指Widget多大就多大【上面情况下设置了Container 的大小,则设置了多大就多大】,Stack.expand使子Widget的大小和父组件一样大【上面情况下,如果设置这个属性,则Container的大小和父级一样大】。
  • overflow : 指子Widget超出Stack时候如何显示,默认值是Overflow.clip, 子Widget超出Stack会被截断。Overflow.visible则超出后会显示。

    未使用Positioned

【alignment】对齐方式。

给大体的 children 子组件设置对齐方式【此处没有Positioned】。
WX20200909-101534.pngWX20200909-101921.pngWX20200909-102531.png
alignment 可设置属性为:

  1. /// The top left corner.
  2. static const Alignment topLeft = Alignment(-1.0, -1.0);
  3. /// The center point along the top edge.
  4. static const Alignment topCenter = Alignment(0.0, -1.0);
  5. /// The top right corner.
  6. static const Alignment topRight = Alignment(1.0, -1.0);
  7. /// The center point along the left edge.
  8. static const Alignment centerLeft = Alignment(-1.0, 0.0);
  9. /// The center point, both horizontally and vertically.
  10. static const Alignment center = Alignment(0.0, 0.0);
  11. /// The center point along the right edge.
  12. static const Alignment centerRight = Alignment(1.0, 0.0);
  13. /// The bottom left corner.
  14. static const Alignment bottomLeft = Alignment(-1.0, 1.0);
  15. /// The center point along the bottom edge.
  16. static const Alignment bottomCenter = Alignment(0.0, 1.0);
  17. /// The bottom right corner.
  18. static const Alignment bottomRight = Alignment(1.0, 1.0);

【fil】设定大小

StackFit.loose是指Widget多大就多大【上面情况下设置了Container 的大小,则设置了多大就多大】,Stack.expand使子Widget的大小和父组件一样大【上面情况下,如果设置这个属性,则Container的大小和父级一样大】

源码和上面一样,就替换了fit相应的值,这里就不贴代码了,以图说话。
WX20200909-110419.pngWX20200909-110949.png

【overflow】在没使用 Positioned 时没啥作用。

下面是使用Positioned时候的作用。

  1. Stack(
  2. fit : StackFit.loose,
  3. // alignment: Alignment.topLeft,
  4. overflow: Overflow.visible,
  5. children : <Widget>[
  6. Container(
  7. width : 200,
  8. height : 200,
  9. color: Colors.green[300],
  10. ),
  11. Positioned(
  12. bottom: -50,
  13. right: -50,
  14. child: Container(
  15. width: 100,
  16. height: 100,
  17. color: Colors.grey[300]
  18. ),
  19. )
  20. ]
  21. ),

WX20200909-115618.pngWX20200909-120453.png

使用Positioned

Positioned的基本属性都有

  1. const Positioned({
  2. Key key,
  3. this.left,
  4. this.top,
  5. this.right,
  6. this.bottom,
  7. this.width,
  8. this.height,
  9. @required Widget child,
  10. }) : assert(left == null || right == null || width == null),
  11. assert(top == null || bottom == null || height == null),
  12. super(key: key, child: child);

上面的属性都是 见名知意 ,这里就不过多的讲解了。

那就直接贴码贴图吧。

【width && height】

  1. Stack(
  2. fit : StackFit.loose,
  3. // alignment: Alignment.topLeft,
  4. overflow: Overflow.visible,
  5. children : <Widget>[
  6. Container(
  7. width : 200,
  8. height : 200,
  9. color: Colors.green[300],
  10. ),
  11. Positioned(
  12. bottom: -50,
  13. right: -50,
  14. width: 300,
  15. height: 200,
  16. child: Container(
  17. width: 100,
  18. height: 100,
  19. color: Color(0x90000000)
  20. ),
  21. )
  22. ]
  23. ),

WX20200909-122720.png
这里你会发现,前面在Positioned中子级Container设置了宽高是有效果。但是在Positioned设置了宽高,则Container是不起效果的。因为在Stack中Container权重没有Positioned权重高。

【left && right && top && bottom】

直接贴码,贴图吧。

  1. class _HomeScene extends State<HomeScene>{
  2. Widget build(BuildContext context){
  3. return Scaffold(
  4. appBar: AppBar(
  5. title: Text("首页"),
  6. centerTitle: true, // 标题是否居中
  7. backgroundColor: Colors.green[400], // 头部背景色。
  8. ),
  9. body: Stack(
  10. alignment: Alignment.topLeft,
  11. overflow: Overflow.visible,
  12. children : <Widget>[
  13. Positioned(
  14. child: Container(
  15. color: Colors.green[100],
  16. ),
  17. ),
  18. Positioned(
  19. top: 50,
  20. // 此处注意
  21. // left: 20,
  22. right: 30,
  23. width: 350,
  24. height: 50,
  25. child: Container(
  26. color: Colors.yellow[200],
  27. alignment: Alignment.center,
  28. child: Text("我是第一个组件"),
  29. ),
  30. ),
  31. Positioned(
  32. top: 100,
  33. bottom: 100,
  34. width: 75,
  35. child: Container(
  36. alignment: Alignment.center,
  37. color: Colors.green[400],
  38. child: Text("第二个组件"),
  39. ),
  40. ),
  41. Positioned(
  42. top: 100,
  43. bottom: 100,
  44. right: 0,
  45. width: 75,
  46. child: Container(
  47. alignment: Alignment.center,
  48. color: Colors.green[400],
  49. child: Text("第三个组件"),
  50. ),
  51. ),
  52. Positioned(
  53. bottom: 50,
  54. right: 30,
  55. width: 350,
  56. height: 50,
  57. child: Container(
  58. alignment: Alignment.center,
  59. color: Colors.yellow[200],
  60. child: Text("第四个组件"),
  61. ),
  62. ),
  63. _Position(context)
  64. ]
  65. ),
  66. );
  67. }
  68. Widget _Position(BuildContext context){
  69. var _context;
  70. _context = Positioned(
  71. top: 110,
  72. bottom: 110,
  73. left: 80,
  74. right: 80,
  75. // bottom: 0,
  76. child: Container(
  77. width: 200,
  78. height: 200,
  79. decoration: BoxDecoration(
  80. color : Colors.black87,
  81. image: DecorationImage(
  82. image: AssetImage("lib/image/img1.jpg"),
  83. )
  84. ) ,
  85. )
  86. );
  87. return _context;
  88. }
  89. }

WX20200909-153933.png
值得关注的就是我这里使用了外部定义的Widget【_Positioned】,当我们代码很多,的时候,在一个容器中书写可能需要几百几千行,你就可以吧这个组件抽离出来写,比较好阅读。

我这有些Positioned书写了width && height属性,但有些没有书写.

是因为你书写width 和 height属性的时候你要注意的是,当你的 widthleft && right 同时存在时候,会报错,当你的 heighttop && bottom 同时存在的时候也会报错。

因为当你的设置了, left top 则他会距离顶部距离单位的时候,则就会空出那么多距离单位

  1. Stack(
  2. children : <Widget>[
  3. Positioned(
  4. child: Container(
  5. color: Colors.green[100],
  6. ),
  7. ),
  8. Positioned(
  9. left: 20.0,
  10. top: 20.0,
  11. child: Container(
  12. color: Colors.yellow[200],
  13. alignment: Alignment.center,
  14. child: Text("我是第一个组件"),
  15. ),
  16. ),
  17. ]
  18. ),

WX20200909-154953.png

当你四个值都设置的时候,则会以父级大小,空出设置距离的位置来填充。

  1. Stack(
  2. children : <Widget>[
  3. Positioned(
  4. child: Container(
  5. color: Colors.green[100],
  6. ),
  7. ),
  8. Positioned(
  9. left: 20.0,
  10. top: 20.0,
  11. right : 20.0,
  12. bottom : 20.0,
  13. child: Container(
  14. color: Colors.yellow[200],
  15. alignment: Alignment.center,
  16. child: Text("我是第一个组件"),
  17. ),
  18. ),
  19. ]
  20. ),

WX20200909-155232.png

那现在载回过来想一想

当你的 widthleft && right 同时存在时候,会报错?因为Flutter都不知道要怎么设置值了。

但是报错信息也是挺直白的,直接

“left == null | right==null | width == null “:is not true.

当你使用Positioned来定位的时候,则Alignment则就不会起效果了。

不管水平方向上还是垂直方向上只要设定了一个值该方向上位置就已经确定过了,aligment对这这个方向上就不会起作用了,如果Positioned 设置了其中任意三个方向的值,这个Widget的位置就是固定的,aligment对它不会起任何作用。