01-1 拥有单个子元素的布局 widget

[toc]

拥有单个子元素的布局 widget

Padding

包裹子 widget 为其添加间距,Padding Widget 的大小是 child 的大小加上 padding。

  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("PaddingWidget"),),
        body: Padding(
//          padding: const EdgeInsets.all(20),// 上左下右 padding 都是 20
          padding: const EdgeInsets.only(left: 20,top: 50,right: 80,bottom: 100),//分别设置
          child: Text("Content"),
        ),
      ),
    );
  }

Center

将 child 放在垂直水平都居中的位置显示。如果没有指定 Center Widget 的大小,那么它就会尽可能的大,类似 match_parent 。如果指定 widthFactor 和 heightFactor 那么它的大小就根据指定的值来设定。例如:widthFactor 指定为 2.0, Center Widget 的宽为 child 宽的 2 倍。

  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("PaddingWidget"),),
        body: Center(
          widthFactor: 2.0,// 宽度为 child 宽的 2 倍
          heightFactor: 2.0,
          child: Container(
            width: 100, // 指定宽度为 100
            height: 100,
            color: Colors.pinkAccent,
          ),
        ),
      ),
    );
  }

Align

将子 widget 根据指定的对齐方式放置在 Align Widget 中,Align Widget 大小计算方式与 Center Widget 相同。

对齐方式 AlignmentGeometry 类型参数可以通过三种方式设置

  1. Alignment 的常量。如:Alignment.topRight 于 Align Widget 上右对齐
  2. Alignment 构造。以 Align Widget 为中心为原点(0,0),参数 x 是 0.5 * child 宽的倍数。y 是 0.5 * child 高的倍数。x 和 y 的取值范围为[-1,1]。
  3. FractionalOffset。以 Align Widget 的左顶点为原点(0,0),参数 x 是 child 宽的倍数。y 是 child 高的倍数。x 和 y 的取值范围为[0,1]。
 Widget build(BuildContext context) {
    TextStyle txtStyle = TextStyle( //文本样式
      fontWeight: FontWeight.bold,
      fontSize: 18.0,
    );
    
    Widget getAlignWidthAlign(AlignmentGeometry align,Color childColor){
      return Align(
        widthFactor: 2.0,
        heightFactor: 2.0,
        alignment: align,
        child: Container(
          width: 50,
          height: 50,
          color: childColor,
        ),
      );
    }
    
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("AlignWidget"),),
        body: Column(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(20),
              child: Text("Const" ,style: txtStyle,),
            ),
            Row(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                getAlignWidthAlign(Alignment.topLeft, Colors.pinkAccent),
                getAlignWidthAlign(Alignment.center, Colors.lightBlueAccent),
                getAlignWidthAlign(Alignment.bottomRight, Colors.lightGreenAccent)
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(20),
              child: Text("Alignment Constructors" ,style: txtStyle,),
            ),
            Row(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                // 原点 即 center 
                getAlignWidthAlign(Alignment(0, 0), Colors.pinkAccent),
                //参数是二分之一 child 宽高的倍数
                // 从中心点向右移动 child 宽度的一半 ,向下移动 child 高度的一半 ,即 rightBottom
                getAlignWidthAlign(Alignment(1, 1), Colors.lightBlueAccent),
                getAlignWidthAlign(Alignment(-1, -1), Colors.lightGreenAccent)
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(20),
              child: Text("FractionalOffset" ,style: txtStyle,),
            ),
            Row(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                //参数是 child 宽高的倍数
                //原点 即 leftTop
                getAlignWidthAlign(FractionalOffset(0, 0), Colors.pinkAccent),
                //向右移动 child 宽度和高度的 0.5 倍,即 center
                getAlignWidthAlign(FractionalOffset(0.5, 0.5), Colors.lightBlueAccent),
                getAlignWidthAlign(FractionalOffset(1, 1), Colors.lightGreenAccent)
              ],
            ),
          ],

        ),
      ),
    );
  }

ConstrainedBox

为 child 添加一个 ConstrainedBox 约束来指定 child 的 minWidth、minHeight、maxWidth、maxHeight。 child 的最终尺寸由 child 的原始 尺寸和约束同时决定,例如 child 宽为 x :

  • x < minWidth => minWidth
  • x > maxWidth => maxWidth
  • minWidth < x < maxWidth => x

高同理。

  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("ConstrainedBox Demo"),),
        body: ConstrainedBox(
            constraints: BoxConstraints(
              minWidth: 50,
              minHeight: 50,
              maxWidth: 200,
              maxHeight: 200,
            ),
            child: Container(
              width: 100, // 指定宽度为 100
              height: 100,
              color: Colors.pinkAccent,
            ),
        ),
      ),
    );
  }

Transform

为 child 添加平移(translate)、缩放(scale)、旋转(rotate)三种转变。

  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("Transform Widget"),),
        body: Transform.translate(// translate 平移
          //offset x 轴方向平移 100, y 轴方向平移100
          offset: Offset(100, 100), 
          child:  Container(
            width: 100, // 指定宽度为 100
            height: 100,
            color: Colors.pinkAccent,
          ),
        ),
      ),
    );
  }
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("Transform Widget"),),
        body: Center(
          child: Transform.rotate(
            //origin 旋转的中心点,默认 child 中点
            origin: Offset(0, 100), //原点向下移动 100 即底边中点
            angle: 45,//顺时针旋转 45度
            child:  Container(
              width: 100, // 指定宽度为 100
              height: 200,
              color: Colors.pinkAccent,
            ),
        ),
        ),
      ),
    );
  }
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar( title: Text("Transform Widget"), ),
          body: Center(
            child: Transform.scale(
              //缩放 倍数
              scale: 2,
              // 默认缩放中点是 child 中点,即 center
              //alignment 和 origin 可以改变缩放中点
              alignment: Alignment.topRight,//缩放中点为右顶点
              origin: Offset(-50, 100),// 将缩放中点左移 50 下移100
              child: Container(
                width: 100, // 指定宽度为 100
                height: 200,
                color: Colors.pinkAccent,
              ),
            ),
          )),
    );
  }

alignment 和 origin 同时存在时缩放中点定位先计算 alignment 再计算 origin。有趣的是当 origin 的 offset 移动超过了 child 的范围时,offset 对缩放中点的影响并不是原来的 x 轴 正右负左,y轴 正下负上。

如图 4 ,alignment 为右顶点,offset(50,100) 此时向右移动超出 child 的范围,x 轴的移动变成了 向左移动 150 (child宽(100) + 50)。

Container

作为最常用的拥有单个子元素的布局 widget,首先 Container 会尽可能的大,类似 match_parent。然后它整合了上面介绍的 widget 功能,可以同时添加 padding、margin、constraints、transform,还可添加 decoration 装饰。

BoxDecoration 盒装饰可以添加边框、边框圆角、背景颜色、背景图片等。

  Widget build(BuildContext context) {

    return MaterialApp(

      home: Scaffold(
        appBar: AppBar(
          title: Text('Container'),
        ),
        body: Container(
            width: 300,
            height: 300,// 宽高
            constraints: BoxConstraints.loose(Size(200, 200)),//约束 Container 宽高不能超过 200
            alignment: Alignment.bottomRight,// Container 中 child 的对齐为右下
            margin: const EdgeInsets.all(30.0),// Container 边距
            padding: const EdgeInsets.all(20.0),// Container 距 child 的间距
            decoration: BoxDecoration(
                border: Border.all( // Container 的边框
                    color: Colors.red,
                    width: 15.0
                ),
                //shape: BoxShape.circle,//shape 为 circle 时不能设置 borderRadius
                // color: Colors.yellow[300], //Container 背景颜色
                borderRadius: const BorderRadius.all(const Radius.circular(30.0)) // 边框圆角
            ),
            transform: Matrix4.translationValues(50, 50, 0),// Container 平移
            child: Container(
              width: 100, // 指定宽度为 100
              height: 100,
              color: Colors.pinkAccent,
            )
        ),
      ),
    );
  }

FittedBox

根据缩放选项(fit)对child 进行缩放,还可以利用 对齐(alignment)来设置 child 的位置。

BoxFit 的枚举值如下,Image 也是用这些枚举值来控制缩放的。

缩放选项 说明 效果
BoxFit.contain 等比缩放,显示的尽可能大
BoxFit.cover 尽可能小,但仍覆盖整个 box
BoxFit.fill 不考虑缩放比例,单纯填满整个 box
BoxFit.fitHeight 等比缩放,使 child 的高和 box 一致
BoxFit.fitWidth 宽一致
BoxFit.none 啥都不做
BoxFit.scaleDown 等比将 child 缩小到 box 可以装下它,如果 box 原本就可以装下它就啥都不做
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("FittedBoxWidget"),),
        body:Container(
          width: 200,
          height: 200,
          child: FittedBox(
            fit: BoxFit.fitWidth,//适应宽度
            alignment: Alignment.topCenter,//上中对齐
            child: Container(
              width: 100, // 指定宽度为 100
              height: 50,
              color: Colors.pinkAccent,
            ),
          ),
        ),
      ),
    );
  }

AspectRatio

按照指定的宽高比设置 child 的大小

  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("AspectRatioWidget"),
        ),
        body: Container(
          // AspectRatio 的 parent 不能指定宽度。
          // 指定宽度后 aspectRatio 失效,怎么设置都会填满 parent
          height: 300,
          child: AspectRatio(
            aspectRatio: 0.5,// 宽高比   1 / 2
            child: Container( // AspectRatio 的 child 指定宽高无效
              width: 1,
              height: 1,
              color: Colors.pinkAccent,
            ),
          ),
        ),
      ),
    );
  }

Baseline

设置一条基线,使 child 根据基线类型与基线对齐。

基线类型(baselineType)

  • TextBaseline.alphabetic :文字底部 , 例如 good 即 g 的底部
  • TextBaseline.ideographic : 文字基线

baselineType 当child 是 Text 时 生效, 如果不是 Text ,则 child 的底部跟 基线对齐。

  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("BaselineWidget"),
        ),
        body: Container(
          width: 200,
          height: 200,
          margin: const EdgeInsets.all(20),
          child: Baseline(
            //基线位置
            baseline: 90,
            //child 是 Text 时 生效; 如果不是 Text ,则 child 的底部跟 基线对齐
            baselineType: TextBaseline.ideographic,
            child: Container(
              width: 100,
              height: 100,
              color: Colors.pinkAccent,
            ),
          ),
        ),
      ),
    );
  }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,776评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,527评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,361评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,430评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,511评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,544评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,561评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,315评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,763评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,070评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,235评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,911评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,554评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,173评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,424评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,106评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,103评论 2 352

推荐阅读更多精彩内容