Flutter进阶—垂直和水平布局

119 篇文章 9 订阅
82 篇文章 1416 订阅

垂直和水平布局

垂直或水平排列控件是最常见的布局模式之一,您可以使用Row(行)控件来水平排列子控件,还可以使用Column(列)控件垂直排列子控件。

要在Flutter中创建行或列,您可以将一个子控件列表添加到Row或Column控件中。反过来,每个子控件本身可以是行或列,依此类推。以下示例显示了如何在行或列中嵌套行或列。

图片保留位置

对齐控件

您可以使用mainAxisAlignment和crossAxisAlignment属性来控制行或列如何对齐其子控件。对于行,主轴水平运行,横轴垂直运行。对于列,主轴垂直运行,横轴水平运行。

这里写图片描述

这里写图片描述

MainAxisAlignment和CrossAxisAlignment类提供了用于控制对齐的各种常量。

在下面示例中,3个图像(pic1.jpgpic2.jpgpic3.jpg)都是100像素的宽度。渲染框(当前指整个屏幕)宽度大于300像素,因此将主轴对齐设置为spaceEvenly可以在每个图像之间,之前和之后均匀分割空闲的水平空间。

这里写图片描述

body: new Center(
  child: new Row(
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    children: [
      new Image.asset('images/pic1.jpg'),
      new Image.asset('images/pic2.jpg'),
      new Image.asset('images/pic3.jpg'),
    ]
  ),
),

列的工作方式与行相同,在下面示例中,显示了1列3张图像,每张图像高100像素。渲染框的高度(当前指整个屏幕)超过300像素,因此将主轴对齐设置为spaceEvenly可以在每个图像之间、上方和下方均匀分割空闲垂直空间。

这里写图片描述

body: new Center(
  child: new Column(
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    children: [
      new Image.asset('images/pic1.jpg'),
      new Image.asset('images/pic2.jpg'),
      new Image.asset('images/pic3.jpg'),
    ]
  ),
),

调整控件

当布局太大而不适合设备时,沿着受影响的边缘会出现红色条纹。例如,以下示例中的行对于设备的屏幕来说太宽了。示例中有3个图像pic1.jpgpic2.jpgpic3.jpg

这里写图片描述

要修复上面中的示例,其中3个图像的行对于其渲染框太宽,并导致红色条带,使用Expanded控件包装每个控件。默认情况下,每个控件的弹性系数为1,将行的三分之一分配给每个窗口小部件。

这里写图片描述

body: new Center(
  child: new Row(
    crossAxisAlignment: CrossAxisAlignment.center,
    children: [
      new Expanded(
        child: new Image.asset('images/pic1.jpg')
      ),
      new Expanded(
        child: new Image.asset('images/pic2.jpg')
      ),
      new Expanded(
        child: new Image.asset('images/pic3.jpg')
      ),
    ]
  ),
),

如果需要一个控件占据其兄弟姐妹两倍的空间,可以将行或列的子控件放置在Expanded控件中,以便沿主轴控制控件的大小。 Expanded控件具有一个flex属性,一个确定控件的弹性系数的整数,Expanded控件的默认flex系数为1。

例如,要创建一组三个控件,其中中间的控件是其他两个控件的两倍,则将中间控件的弹性系数设置为2:

这里写图片描述

body: new Center(
  child: new Row(
    crossAxisAlignment: CrossAxisAlignment.center,
    children: [
      new Expanded(
        child: new Image.asset('images/pic1.jpg')
      ),
      new Expanded(
        flex: 2,
        child: new Image.asset('images/pic2.jpg')
      ),
      new Expanded(
        child: new Image.asset('images/pic3.jpg')
      ),
    ]
  ),
),

包装控件

默认情况下,行或列在其主轴上占用的空间尽可能多,但如果要将子控件紧密包装在一起,则将其mainAxisSize设置为MainAxisSize.min。以下示例使用此属性将星形图标打包在一起。

这里写图片描述

@override
Widget build(BuildContext context) {
  Widget packedRow = new Row(
    mainAxisSize: MainAxisSize.min,
    children: [
      new Icon(Icons.star, color: Colors.green[500]),
      new Icon(Icons.star, color: Colors.green[500]),
      new Icon(Icons.star, color: Colors.green[500]),
      new Icon(Icons.star, color: Colors.black),
      new Icon(Icons.star, color: Colors.black),
    ]
  );
  return new Scaffold(
    appBar: new AppBar(
      title: new Text(widget.title),
    ),
    body: new Center(
      child: packedRow,
    ),
  );
}

嵌套行和列

占位哈!

概述的部分实现为两行,评分行包含五颗星和评论数,图标行包含三列图标和文本。

评分行的控件树:

这里写图片描述

ratings变量创建一行包含较小的5颗星图标和文本:

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    //...
    Widget ratings = new Container(
        padding: new EdgeInsets.all(20.0),
        child: new Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              new Row(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    new Icon(Icons.star, color: Colors.black),
                    new Icon(Icons.star, color: Colors.black),
                    new Icon(Icons.star, color: Colors.black),
                    new Icon(Icons.star, color: Colors.black),
                    new Icon(Icons.star, color: Colors.black),
                  ]
              ),
              new Text(
                  '233个评论',
                  style: new TextStyle(
                      color: Colors.black,
                      fontWeight: FontWeight.w800,
                      fontFamily: 'Roboto',
                      letterSpacing: 0.5,
                      fontSize: 13.0,
                  )
              )
            ]
        ),
    );
    //...
  }
}

评级行下方的图标行包含3列,每列包含一个图标和两行文本,您可以在其控件树中看到:

这里写图片描述

iconList变量定义图标行:

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    //...
    TextStyle descTextStyle = new TextStyle(
        color: Colors.black,
        fontWeight: FontWeight.w800,
        fontFamily: 'Roboto',
        letterSpacing: 0.5,
        fontSize: 13.0,
        height: 2.0,
    );
    // DefaultTextStyle.merge允许您创建一个默认文本,由子控件和所有后续子控件继承的风格
    var iconList = DefaultTextStyle.merge(
        style: descTextStyle,
        child: new Container(
            padding: new EdgeInsets.all(5.0),
            child: new Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  new Column(
                      children: [
                        new Icon(Icons.kitchen, color: Colors.green[500]),
                        new Text('食材:'),
                        new Text('30分钟'),
                      ]
                  ),
                  new Column(
                      children: [
                        new Icon(Icons.timer, color: Colors.green[500]),
                        new Text('烹饪:'),
                        new Text('5分钟'),
                      ]
                  ),
                  new Column(
                      children: [
                        new Icon(Icons.restaurant, color: Colors.green[500]),
                        new Text('品尝:'),
                        new Text('25分钟'),
                      ]
                  ),
                ]
            )
        )
    );
    //...
  }
}

titleText和subTitle变量定义标题文本和内容文本:

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    //...
    Container titleText = new Container(
        padding: new EdgeInsets.all(10.0),
        child: new Text(
            '黑椒牛排',
            style: new TextStyle(
                fontWeight: FontWeight.w800,
                letterSpacing: 0.5,
                fontSize: 20.0,
            )
        )
    );
    Text subTitle = new Text(
        '去超市买两块上好的牛排也不是很贵,至少比在外面吃要便宜很多。用黑胡椒碎、百里香、鼠尾草、迷迭香等混合成的香草料腌制提香味,大蒜、洋葱末去腥提鲜,柠檬汁去腥提味;在家也能打造出和西餐厅一样美味的黑椒香草牛排。咱也喝点红酒,看着电视,吃着牛排,感觉也不错呀!',
        textAlign: TextAlign.center,
        style: new TextStyle(
            fontFamily: 'Georgia',
            fontSize: 15.0,
        )
    );
    //...
  }
}

leftColumn变量包含评分和图标行,以及描述牛排的标题和文本:

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    //...
    Container leftColumn = new Container(
        padding: new EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 10.0),
        child: new Column(
            children: [
              titleText,
              subTitle,
              ratings,
              iconList,
            ]
        )
    );
    //...
  }
}

你可以使用Image.network从网络中获取图像,但是,在这个示例中,图像(beefsteak.jpg)是保存到项目中的图像目录中,添加到pubspec文件中,并使用Images.asset访问。

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    //...
    var mainImage = new Image.asset(
        'images/beefsteak.jpg',
        fit: BoxFit.cover,
    );
    //...
  }
}

左列放在容器中以约束其宽度,最后,用户界面是用一个卡片内的一行(包含左栏和图像)构成的。

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    //...
    body: new Center(
        child: new Container(
            margin: new EdgeInsets.fromLTRB(0.0, 5.0, 0.0, 5.0),
            child: new Card(
                child: new Row(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      new Container(
                          width: 440.0,
                          child: leftColumn,
                      ),
                      mainImage,
                    ]
                )
            )
        )
      ),
    //...
  }
}

这里写图片描述

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

何小有

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值