Flutter学习笔记(23)--多个子元素的布局Widget(Rwo、Column、Stack、IndexedStack、Table、Wrap)

时间:2024-01-25 07:55:22

如需转载,请注明出处:Flutter学习笔记(23)--多个子元素的布局Widget(Rwo、Column、Stack、IndexedStack、Table、Wrap)

 

上一篇梳理了拥有单个子元素布局的Widget,今天来梳理一下拥有多个子元素布局的Widget。

  • Row

Row组件常见属性如下:

mainAxisAlignment:主轴的排列方式

crossAxisAlignment:次轴的排列方式

mainAxisSize:主轴应该占据多少空间,取值max为最大,min为最小

children:组件子元素,它的本质是一个List列表

对于Row来说,水平方向是主轴,垂直方向是次轴。

首先来看一下mainAxisAlignment属性值都有哪些

enum MainAxisAlignment {
  start,//将子控件放在主轴开始的位置
  end,//将子控件放在主轴结束的位置
  center,//将子控件放在主轴中间的位置
  spaceBetween,//将主轴空白位置进行均分,排列子元素,首尾没有空隙
  spaceAround,//将主轴空白区域均分,使中间各个子控件间距相等,首尾子控件间距为中间子控件间距的一半
  spaceEvenly,//将主轴空白区域均分,使各个子空间间距相等
}

Demo示例:

import 'package:flutter/material.dart';

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

class DemoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Children Demo',
      home: new Scaffold(
        appBar: AppBar(
          title: new Text('Children Demo'),
        ),
        body: new Row(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: <Widget>[
            new Text('11111111111'),
            new Text('22222222222'),
            new Text('33333333333')
          ],
        ),
      ),
    );
  }
}

  • Column

Column组件常见属性如下:

mainAxisAlignment:主轴的排列方式

crossAxisAlignment:次轴的排列方式

mainAxisSize:主轴应该占据多少空间,取值max为最大,min为最小

children:组件子元素,它的本质是一个List列表

对Column来说,垂直方向是主轴,水平方向是次轴,使用上和Row大同小异

Demo示例:

import 'package:flutter/material.dart';

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

class DemoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Children Demo',
      home: new Scaffold(
        appBar: AppBar(
          title: new Text('Children Demo'),
        ),
        body: new Column(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: <Widget>[
            new Text('11111111111'),
            new Text('22222222222'),
            new Text('33333333333')
          ],
        ),
      ),
    );
  }
}

  • Stack

Stack/alignment:

Stack组件的每一个子组件要么定位,要么不定位,定位的子组件是用Positioned组件包裹的,Stack组件本身包含所有不定位的子组件,子组件根据alignment属性定位(默认为左上角)。然后根据定位的子组件的top、right、bottom、left属性将他们放置在Stack组件上。

Stack既然是允许子元素堆叠的组件,那么定位堆叠位置的属性值有哪些呢?

alignment属性值:bottomCenter 底部中间位置、bottomLeft 底部左侧位置、bottomRight 底部右侧位置、center 正中间位置、centerLeft 中间居左位置、centerRight 中间居右位置、topCenter 上部居中位置、topLeft 上部居左位置、topRight 上部居右位置

Demo示例:

import 'package:flutter/material.dart';

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

class DemoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Children Demo',
      home: new Scaffold(
        appBar: AppBar(
          title: new Text('Children Demo'),
        ),
        body: new Center(
          child: new Stack(
            alignment: Alignment.centerLeft,
            children: <Widget>[
              new Container(
                width: 200.0,
                height: 200.0,
                color: Colors.blue,
              ),
              new Text('这是一段文本')
            ],
          ),
        ),
      ),
    );
  }
}

Stack/Positioned:

上面的示例是通过系统提供的定位来给子元素进行堆叠,但是实际工作中,上面的几类属性值往往不能满足我们UI的需求,UI可能会要求子元素放在任何你想不到的位置,那么这时候就需要用到我们Positioned来进行定位了。

Positioned属性值:top 子元素相对顶部边界距离,left 子元素相对左侧边界距离,right 子元素相对右侧边界距离,bottom 子元素相对底部边界距离。

Demo示例:

import 'package:flutter/material.dart';

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

class DemoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Children Demo',
      home: new Scaffold(
        appBar: AppBar(
          title: new Text('Children Demo'),
        ),
        body: new Center(
          child: new Stack(
            children: <Widget>[
              new Container(
                width: 200.0,
                height: 200.0,
                color: Colors.blue,
              ),
              new Positioned(
                top: 20.0,
                left: 50.0,
                child: new Text('这是一段文本')
              )
            ],
          ),
        ),
      ),
    );
  }
}

  • IndexedStack

IndexedStack继承自Stack,它的作用是显示第index个child,其他的child都是不可见的,所以IndexedStack的尺寸永远是和最大的子节点尺寸一致。由于IndexedStack是继承自Stack,所以它只比Stack多了一个index属性,即对应child的索引。

Demo示例:

import 'package:flutter/material.dart';

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

class DemoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Children Demo',
      home: new Scaffold(
        appBar: AppBar(
          title: new Text('Children Demo'),
        ),
        body: new Center(
          child: new IndexedStack(
            index: 1,
            children: <Widget>[
              new Container(
                width: 200.0,
                height: 200.0,
                color: Colors.blue,
              ),
              new Positioned(
                top: 20.0,
                left: 50.0,
                child: new Text('这是一段文本')
              )
            ],
          ),
        ),
      ),
    );
  }
}

  • Table

Table表格布局,每一行的高度由其内容决定,每一列的宽度由columnWidths属性单独控制。

Table组件常见属性如下:

columnWidths:设置每一列的宽度。

defaultColumnWidth:默认的每一列宽度,默认情况下均分。

textDirection:文字方向。

border:表格边框。

defaultVerticalAlignment:默认垂直方向的对齐方式,top 放置在顶部、middle 垂直居中、bottom 放置在底部、baseline 文本baseline对齐、fill 充满整个cell

import 'package:flutter/material.dart';

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

class DemoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Children Demo',
      home: new Scaffold(
        appBar: AppBar(
          title: new Text('Children Demo'),
        ),
        body: new Table(
          defaultVerticalAlignment: TableCellVerticalAlignment.bottom,
          // 设置表格有多少列,并且指定列宽
          columnWidths:const <int,TableColumnWidth> {
            0:FixedColumnWidth(40.0),
            1:FixedColumnWidth(40.0),
            2:FixedColumnWidth(60.0),
            3:FixedColumnWidth(60.0),
            4:FixedColumnWidth(130.0),
          },
          // 设置表格边框样式
          border: TableBorder.all(
            color: Colors.blue,
            width: 2.0,
            style: BorderStyle.solid
          ),
          children: const <TableRow>[
            // 添加第一行数据
            TableRow(
              children: <Widget>[
                SizedBox(
                  child: Text('姓名'),
                  height: 30,
                ),
                Text('性别'),
                Text('年龄'),
                Text('身高'),
                Text('备注'),
              ],
            ),
            // 添加第二行数据
            TableRow(
              children: <Widget>[
                Text('张三'),
                Text(''),
                Text('20'),
                Text('186'),
                Text('学渣'),
              ],
            ),
            // 添加第三行数据
            TableRow(
              children: <Widget>[
                Text('李四'),
                Text(''),
                Text('20'),
                Text('188'),
                Text('学酥'),
              ],
            ),
            // 添加第四行数据
            TableRow(
              children: <Widget>[
                Text('王五'),
                Text(''),
                Text('21'),
                Text('177'),
                Text('学霸'),
              ],
            ),
            // 添加第五行数据
            TableRow(
              children: <Widget>[
                Text('小梅'),
                Text(''),
                Text('22'),
                Text('170'),
                Text('学神,需要重点培养'),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

  • Wrap

import 'package:flutter/material.dart';

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

class DemoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Children Demo',
      home: new Scaffold(
        appBar: AppBar(
          title: new Text('Children Demo'),
        ),
        body: new Wrap(
          spacing: 3.0,
          runSpacing: 20.0,//纵轴方向的间距
          alignment: WrapAlignment.end,//纵轴方向的对其方式
          children: <Widget>[
            new Chip(
              avatar: CircleAvatar(
                backgroundColor: Colors.blue,
                child: new Text('A'),
              ),
              label: new Text('文本一'),
            ),
            new Chip(
              avatar: CircleAvatar(
                backgroundColor: Colors.blue,
                child: new Text('B'),
              ),
              label: new Text('文本二'),
            ),
            new Chip(
              avatar: CircleAvatar(
                backgroundColor: Colors.blue,
                child: new Text('C'),
              ),
              label: new Text('文本三'),
            ),
            new Chip(
              avatar: CircleAvatar(
                backgroundColor: Colors.blue,
                child: new Text('D'),
              ),
              label: new Text('文本四'),
            ),
            new Chip(
              avatar: CircleAvatar(
                backgroundColor: Colors.blue,
                child: new Text('E'),
              ),
              label: new Text('文本五'),
            ),
          ],
        ),
      ),
    );
  }
}