Flutter布局方式(2)-Stack和Position

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,),
          ],
        ),
      ),
    );
  }
}
運行結(jié)果.png

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.expand

如果指定是StackFit.loose袭祟,所以子Widget 多大就多大.

StackFit.loose

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("第三個組件"),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
Position

這個地方有注意地方辑舷,例如說第一個組件我指定距離左邊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.bottomEnd

②.AlignmentDirectional.topEnd

AlignmentDirectional.bottomEnd的方式是從左上角為基準開始對齊:

AlignmentDirectional.topEnd

③.AlignmentDirectional.center

AlignmentDirectional.center的方式是以stack的中心位置:

AlignmentDirectional.center

④.AlignmentDirectional.centerEnd

所有的Widget 在Stack的中心位置并且右邊跟stack右邊挨著

AlignmentDirectional.centerEnd

⑤.AlignmentDirectional.centerStart

所有的Widget 在Stack的中心位置并且左邊跟stack左邊挨著

AlignmentDirectional.centerStart

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("第三個組件"),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
使用postioned定位的情況

這種情況是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("第三個組件"),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
AlignmentDirectional.bottomEnd

會發(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影響的珍昨,所以第二組件展示的位置就是圖片上展示的位置.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末县耽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子镣典,更是在濱河造成了極大的恐慌兔毙,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兄春,死亡現(xiàn)場離奇詭異澎剥,居然都是意外死亡,警方通過查閱死者的電腦和手機赶舆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門哑姚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來祭饭,“玉大人,你說我怎么就攤上這事叙量〕” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵宛乃,是天一觀的道長悠咱。 經(jīng)常有香客問我蒸辆,道長征炼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任躬贡,我火速辦了婚禮谆奥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拂玻。我一直安慰自己酸些,他們只是感情好,可當我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布檐蚜。 她就那樣靜靜地躺著魄懂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪闯第。 梳的紋絲不亂的頭發(fā)上市栗,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天,我揣著相機與錄音咳短,去河邊找鬼填帽。 笑死,一個胖子當著我的面吹牛咙好,可吹牛的內(nèi)容都是我干的篡腌。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼勾效,長吁一口氣:“原來是場噩夢啊……” “哼嘹悼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起层宫,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤杨伙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后卒密,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缀台,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年哮奇,在試婚紗的時候發(fā)現(xiàn)自己被綠了膛腐。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片睛约。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖哲身,靈堂內(nèi)的尸體忽然破棺而出辩涝,到底是詐尸還是另有隱情,我是刑警寧澤勘天,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布怔揩,位于F島的核電站,受9級特大地震影響脯丝,放射性物質(zhì)發(fā)生泄漏商膊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一宠进、第九天 我趴在偏房一處隱蔽的房頂上張望晕拆。 院中可真熱鬧,春花似錦材蹬、人聲如沸实幕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽昆庇。三九已至,卻和暖如春闸溃,著一層夾襖步出監(jiān)牢的瞬間整吆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工圈暗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留掂为,地道東北人。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓员串,卻偏偏與公主長得像勇哗,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子寸齐,可洞房花燭夜當晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容