Flutter学习第三课-布局组件 Container Padding Align Center Offstage Baseline

目录

Container
Padding
Align
Center
Offstage
Baseline

Container

Container在Flutter最常用的组件。是一个结合了绘制(painting)、定位(positioning)以及尺寸(sizing)widget的widget。

组成
  • Container的组成如下:
  1. 最里层的是child元素;
  2. child元素首先会被padding包着;
  3. 然后添加额外的constraints限制;
  4. 最后添加margin。
  • Container的绘制的过程如下:
  1. 首先会绘制transform效果;
  2. 接着绘制decoration;
  3. 然后绘制child;
  4. 最后绘制foregroundDecoration。
  • Container自身尺寸的调节分两种情况:
  1. Container在没有子节点(children)的时候,会试图去变得足够大。除非constraints是unbounded限制,在这种情况下,Container会试图去变得足够小。
  2. 带子节点的Container,会根据子节点尺寸调节自身尺寸,但是Container构造器中如果包含了width、height以及constraints,则会按照构造器中的参数来进行尺寸的调节。
布局行为
  • 由于Container组合了一系列的widget,这些widget都有自己的布局行为,因此Container的布局行为有时候是比较复杂的。
  • 一般情况下,Container会遵循如下顺序去尝试布局:
  1. 对齐(alignment);
  2. 调节自身尺寸适合子节点;
  3. 采用width、height以及constraints布局;
  4. 扩展自身去适应父节点;
  5. 调节自身到足够小。
  • 进一步说:
  1. 如果没有子节点、没有设置width、height以及constraints,并且父节点没有设置unbounded的限制,Container会将自身调整到足够小。
  2. 如果没有子节点、对齐方式(alignment),但是提供了width、height或者constraints,那么Container会根据自身以及父节点的限制,将自身调节到足够小。
  3. 如果没有子节点、width、height、constraints以及alignment,但是父节点提供了bounded限制,那么Container会按照父节点的限制,将自身调整到足够大。
  4. 如果有alignment,父节点提供了unbounded限制,那么Container将会调节自身尺寸来包住child;
  5. 如果有alignment,并且父节点提供了bounded限制,那么Container会将自身调整的足够大(在父节点的范围内),然后将child根据alignment调整位置;
  6. 含有child,但是没有width、height、constraints以及alignment,Container会将父节点的constraints传递给child,并且根据child调整自身。
  • 另外,margin以及padding属性也会影响到布局
  Container({
    Key key,
    this.alignment,
    this.padding,
    Color color,
    Decoration decoration,
    this.foregroundDecoration,
    double width,
    double height,
    BoxConstraints constraints,
    this.margin,
    this.transform,
    this.child,
  }) 
  • key:Container唯一标识符,用于查找更新。
  • alignment:控制child的对齐方式,如果container或者container父节点尺寸大于child的尺寸,这个属性设置会起作用,有很多种对齐方式。
  • padding:decoration内部的空白区域,如果有child的话,child位于padding内部。padding与margin的不同之处在于,padding是包含在content内,而margin则是外部边界,设置点击事件的话,padding区域会响应,而margin区域不会响应。
  • color:用来设置container背景色,如果foregroundDecoration设置的话,可能会遮盖color效果。
  • decoration:绘制在child后面的装饰,设置了decoration的话,就不能设置color属性,否则会报错,此时应该在decoration中进行颜色的设置。
  • foregroundDecoration:绘制在child前面的装饰。
  • width:container的宽度,设置为double.infinity可以强制在宽度上撑满,不设置,则根据child和父节点两者一起布局。
  • height:container的高度,设置为double.infinity可以强制在高度上撑满。
  • constraints:添加到child上额外的约束条件。
  • margin:围绕在decoration和child之外的空白区域,不属于内容区域。
  • transform:设置container的变换矩阵,类型为Matrix4。
  • child:container中的内容widget。
Padding

Padding在Flutter中用的也挺多的,作为一个基础的控件,功能非常单一,给子节点设置padding属性。写过其他端的都了解这个属性,就是设置内边距属性,内边距的空白区域,也是widget的一部分。

布局行为
  • Padding的布局分为两种情况:
  1. 当child为空的时候,会产生一个宽为left+right,高为top+bottom的区域;
  2. 当child不为空的时候,Padding会将布局约束传递给child,根据设置的padding属性,缩小child的布局尺寸。然后Padding将自己调整到child设置了padding属性的尺寸,在child周围创建空白区域。
  const Padding({
    Key key,
    @required this.padding,
    Widget child,
  })
  • padding:padding的类型为EdgeInsetsGeometry,EdgeInsetsGeometry是EdgeInsets以及EdgeInsetsDirectional的基类。在实际使用中不涉及到国际化,例如适配阿拉伯地区等,一般都是使用EdgeInsets。EdgeInsetsDirectional光看命名就知道跟方向相关,因此它的四个边距不限定上下左右,而是根据方向来定的。
Align

在其他端的开发,Align一般都是当做一个控件的属性,并没有拿出来当做一个单独的控件。Align本身实现的功能并不复杂,设置child的对齐方式,例如居中、居左居右等,并根据child尺寸调节自身尺寸。

布局行为
  • Align的布局行为分为两种情况:
  1. 当widthFactor和heightFactor为null的时候,当其有限制条件的时候,Align会根据限制条件尽量的扩展自己的尺寸,当没有限制条件的时候,会调整到child的尺寸;
  2. 当widthFactor或者heightFactor不为null的时候,Aligin会根据factor属性,扩展自己的尺寸,例如设置widthFactor为2.0的时候,那么,Align的宽度将会是child的两倍。

Align为什么会有这样的布局行为呢?原因很简单,设置对齐方式的话,如果外层元素尺寸不确定的话,内部的对齐就无法确定。因此,会有宽高因子、根据外层限制扩大到最大尺寸、外层不确定时调整到child尺寸这些行为。

  const Align({
    Key key,
    this.alignment = Alignment.center,
    this.widthFactor,
    this.heightFactor,
    Widget child,
  }) 
  • alignment:对齐方式,一般会使用系统默认提供的9种方式,但是并不是说只有这9种,例如如下的定义。系统提供的9种方式只是预先定义好的。
  • The top left corner.
    static const Alignment topLeft = const Alignment(-1.0, -1.0);
  • Alignment实际上是包含了两个属性的,其中第一个参数,-1.0是左边对齐,1.0是右边对齐,第二个参数,-1.0是顶部对齐,1.0是底部对齐。根据这个规则,我们也可以自定义我们需要的对齐方式,例如
  • 居右高于底部1/4处.
    static const Alignment rightHalfBottom = alignment: const Alignment(1.0, 0.5),
  • widthFactor:宽度因子,如果设置的话,Align的宽度就是child的宽度乘以这个值,不能为负数。
  • heightFactor:高度因子,如果设置的话,Align的高度就是child的高度乘以这个值,不能为负数。
Center

继承制Align 并强制 this.alignment = Alignment.center;其他与Align一摸一样。

Offstage

Offstage的作用很简单,通过一个参数,来控制child是否显示,日常使用中也算是比较常用的控件。

布局行为
  • Offstage的布局行为完全取决于其offstage参数
  1. 当offstage为true,当前控件不会被绘制在屏幕上,不会响应点击事件,也不会占用空间;
  2. 当offstage为false,当前控件则跟平常用的控件一样渲染绘制;
    另外,当Offstage不可见的时候,如果child有动画,应该手动停掉,Offstage并不会停掉动画。
Baseline

Baseline这个控件,做过移动端开发的都会了解过,一般文字排版的时候,可能会用到它。它的作用很简单,根据child的baseline,来调整child的位置。例如两个字号不一样的文字,希望底部在一条水平线上,就可以使用这个控件,是一个非常基础的控件。

布局行为
  • Baseline控件布局行为分为两种情况:
    1.如果child有baseline,则根据child的baseline属性,调整child的位置;
    2.如果child没有baseline,则根据child的bottom,来调整child的位置。
  const Baseline({
    Key key,
    @required this.baseline,
    @required this.baselineType,
    Widget child,
  })
  • baseline:baseline数值,必须要有,从顶部算。
  • baselineType:bseline类型,也是必须要有的,目前有两种类型:
    alphabetic:对齐字符底部的水平线;
    ideographic:对齐表意字符的水平线。
    在这里插入图片描述
/*
  Container({
    Key key,
    this.alignment,
    //控制child的对齐方式,如果container或者container父节点尺寸大于child的尺寸,
    这个属性设置会起作用,有很多种对齐方式。
    this.padding,
    //decoration内部的空白区域,如果有child的话,child位于padding内部。
    padding与margin的不同之处在于,padding是包含在content内,而margin则是外部边界,
    设置点击事件的话,padding区域会响应,而margin区域不会响应。
    Color color,//用来设置container背景色,如果foregroundDecoration设置的话,可能会遮盖color效果。
    Decoration decoration,
    //绘制在child后面的装饰,设置了decoration的话,就不能设置color属性,
    否则会报错,此时应该在decoration中进行颜色的设置。
    this.foregroundDecoration,//绘制在child前面的装饰。
    double width,//container的宽度,设置为double.infinity可以强制在宽度上撑满,不设置,则根据child和父节点两者一起布局。
    double height,//container的高度,设置为double.infinity可以强制在高度上撑满。
    BoxConstraints constraints,//添加到child上额外的约束条件。
    this.margin,//围绕在decoration和child之外的空白区域,不属于内容区域。
    this.transform,//设置container的变换矩阵,类型为Matrix4。
    this.child,
  })
  const Padding({
    Key key,
    @required this.padding,
    //padding的类型为EdgeInsetsGeometry,EdgeInsetsGeometry是EdgeInsets以及EdgeInsetsDirectional的基类。
    在实际使用中不涉及到国际化,例如适配阿拉伯地区等,一般都是使用EdgeInsets。
    EdgeInsetsDirectional光看命名就知道跟方向相关,因此它的四个边距不限定上下左右,而是根据方向来定的。
    Widget child,
  })
  const Align({
    Key key,
    this.alignment = Alignment.center,
    this.widthFactor,
    this.heightFactor,
    Widget child,
  })
  const Baseline({
    Key key,
    @required this.baseline,//baseline数值,必须要有,从顶部算。
    @required this.baselineType,
    //bseline类型,也是必须要有的,目前有两种类型:
      alphabetic:对齐字符底部的水平线;
      ideographic:对齐表意字符的水平线。
    Widget child,
  })
*/
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  var _offstage = true;
  var _offstageRes  = "offstage_off";

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      title: "Flutter Demo",
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: Text("Container Padding Align Center Offstage Sample"),
        ),
        body: Column(
          children: <Widget>[
            new Container(
              constraints: new BoxConstraints.expand(
                height:
                    Theme.of(context).textTheme.display1.fontSize * 1.1 + 200.0,
              ),
              decoration: new BoxDecoration(
                border: new Border.all(width: 2.0, color: Colors.red),
                color: Colors.greenAccent,
                borderRadius: new BorderRadius.all(new Radius.circular(20.0)),
                image: new DecorationImage(
                  image: new NetworkImage(
                      'https://profile.csdnimg.cn/E/8/A/3_chen1234219'),
                  centerSlice: new Rect.fromLTRB(0.0, 0.0, 5.0, 5.0),
                ),
              ),
              padding: const EdgeInsets.all(30.0),
              alignment: Alignment.center,
              child: new Text('Container',
                  style: Theme.of(context)
                      .textTheme
                      .display1
                      .copyWith(color: Colors.black)),
              transform: new Matrix4.rotationZ(-0.05),
            ),
            new Padding(
              padding: new EdgeInsets.all(8.0),
              child: const Card(child: const Text('Padding')),
            ),
            new Align(
              alignment: Alignment.centerLeft,
              widthFactor: 4.0,
              heightFactor: 5.0,
              child: new Text("Align"),
            ),
            new Center(
              child: new Text("Center"),
            ),
            Offstage(
              offstage: _offstage,
              child: Container(alignment:Alignment.center,color: Colors.blue, height: 50.0,child: new Text("Offstage"),),
            ),
            new Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                new Baseline(
                  baseline: 50.0,
                  baselineType: TextBaseline.alphabetic,
                  child: new Text(
                    'Baseline',
                    style: new TextStyle(
                      fontSize: 20.0,
                      textBaseline: TextBaseline.alphabetic,
                    ),
                  ),
                ),
                new Baseline(
                  baseline: 50.0,
                  baselineType: TextBaseline.alphabetic,
                  child: new Container(
                    width: 30.0,
                    height: 30.0,
                    color: Colors.red,
                  ),
                ),
              ],
            )
          ],
        ),
        floatingActionButton: FloatingActionButton.extended(
          onPressed: () {
            setState(() {
              _offstage = !_offstage;
              if(_offstage){
                _offstageRes = "offstage_on";
              }else{
                _offstageRes = "offstage_off";
              }
            });
          },
          label: Text('$_offstageRes'),
          icon: Icon(Icons.thumb_up),
          backgroundColor: Colors.pink,
        ),
      ),
    );
  }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值