[Flutter]flutter基础之组件基础(十)

一、Table Widget

Table 是一个使用表格布局算法布局子 Widget 的 Widget 。Table 的行根据其内容垂直调整大小。 若要控制列宽,使用 columnWidths 属性。

1
Table({
2
  Key key,
3
  //List<TableRow>类型可选命名参数,表格每一行
4
  this.children = const <TableRow>[],
5
  //Map<int, TableColumnWidth>类型可选命名参数,如何确定此表的列的水平范围
6
  this.columnWidths,
7
  //TableColumnWidth类型可选命名参数,如何确定没有显式大小调整算法的列的宽度
8
  this.defaultColumnWidth = const FlexColumnWidth(1.0),
9
  //TextDirection类型可选命名参数,列的排列方向
10
  this.textDirection,
11
  //TableBorder类型可选命名参数,为表格边框和内部分割线的样式
12
  this.border,
13
  //TableCellVerticalAlignment类型可选命名参数,未明确指定垂直对齐方式的单元格如何垂直对齐
14
  this.defaultVerticalAlignment = TableCellVerticalAlignment.top,
15
  //TextBaseline类型可选命名参数,使用TableCellVerticalAlignment.baseline对齐行时要使用的文本基线
16
  this.textBaseline,
17
})

TableRow 用于设置表格中一组水平单元格,表格中每一行必须有相同数量的子 Widget ,可以使用 TableCell 控制一行中单元格的对齐方式。其构造方法如下:

1
const TableRow({ 
2
  this.key,
3
  //Decoration类型可选命名参数,行的背景装饰
4
  this.decoration,
5
  //List<Widget>类型可选命名参数,组成此行中单元格的Widget
6
  this.children 
7
});

TableColumnWidth 是一个抽象类,用于描述列宽度,可以使用其子类进行设置。如果要设置固定宽度的列可以使用 FixedColumnWidth 。相对宽度可使用 FlexColumnWidthFractionColumnWidthFlexColumnWidth 用于设置在其他列都已经设置好的情况下,剩余列宽度的大小。如果有多个 FlexColumnWidth 列,则会根据其设置的数值比例分配宽度。FractionColumnWidth 用来根据百分比设置列宽度,设置的列宽度为表格宽度乘以设置的百分比数值。IntrinsicColumnWidth 用来根据单元格的内容自动调整宽度,关于类似的说明在上篇文章提高多,此类应尽量少用,布局开销比较大,不能设置参数。 MaxColumnWidthMinColumnWidth 有两个参数,为 TableColumnWidth 类型,可以使用以上的子类,分别用于设置两个尺寸中最大和最小的宽度。

TableBorder 用于设置表格的边框样式,有几个构造方法如下:

1
//分别设置表格边框
2
const TableBorder({
3
  //BorderSide类型可选命名参数,顶部边框样式
4
  this.top = BorderSide.none,
5
  //BorderSide类型可选命名参数,右侧边框样式
6
  this.right = BorderSide.none,
7
  //BorderSide类型可选命名参数,底部边框样式
8
  this.bottom = BorderSide.none,
9
  //BorderSide类型可选命名参数,左侧边框样式
10
  this.left = BorderSide.none,
11
  //BorderSide类型可选命名参数,横向边框样式
12
  this.horizontalInside = BorderSide.none,
13
  //BorderSide类型可选命名参数,纵向边框样式
14
  this.verticalInside = BorderSide.none,
15
});
16
17
//设置统一边框
18
factory TableBorder.all({
19
  //Color类型可选命名参数,边框颜色
20
  Color color = const Color(0xFF000000),
21
  //double类型可选命名参数,边框宽度
22
  double width = 1.0,
23
  //BorderStyle类型可选命名参数,边框线条样式
24
  BorderStyle style = BorderStyle.solid,
25
})
26
  
27
//分别设置表格内边框和外边框
28
factory TableBorder.symmetric({
29
  //BorderSide类型可选命名参数,表格内边框
30
  BorderSide inside = BorderSide.none,
31
  //BorderSide类型可选命名参数,表格外边框
32
  BorderSide outside = BorderSide.none,
33
})

BorderSide 用于设置某一侧的边框,构造方法如下:

1
const BorderSide({
2
  //Color类型可选命名参数,边框颜色
3
  this.color = const Color(0xFF000000),
4
  //ouble类型可选命名参数,边框宽度
5
  this.width = 1.0,
6
  //BorderStyle类型可选命名参数,边框样式
7
  this.style = BorderStyle.solid,
8
})

BorderStyle 为边框的线条样式,是一个枚举类型值,如下:

1
enum BorderStyle {
2
  //无样式
3
  none,
4
  //实线
5
  solid,
6
}

TableCellVerticalAlignment 用于设置单元格的垂直对齐方式,是一个枚举类型值,如下:

1
enum TableCellVerticalAlignment {
2
  //顶部对齐
3
  top,
4
  //居中对齐
5
  middle,
6
  //底部对齐
7
  bottom,
8
  //对齐具有此对齐方式的单元,以使它们都共享相同的基线。 没有基线的单元格将顶部对齐。 
9
  //使用的基线由RenderTable.textBaseline指定。 如果未指定RenderTable.textBaseline
10
  //则使用基线值无效。这种垂直对齐方式比较昂贵,因为它会使表格为该行中的每个单元格计算基线
11
  baseline,
12
  //具有此对齐方式的单元格的大小应与该行一样高,然后使其适合该行。
13
  //如果所有单元格都具有此对齐方式,则该行的高度将为零
14
  fill
15
}

Table 使用方式如下:

1
class MyHomePage extends StatelessWidget {
2
  @override
3
  Widget build(BuildContext context) {
4
    // TODO: implement build
5
    return Scaffold(
6
      appBar: AppBar(
7
        title: Text("HomePage"),
8
      ),
9
      body: Table(						//Table
10
        children: <TableRow>[
11
          TableRow(children: <Widget>[Text("Text1 Text1 Text1"), Text("Text2"), Text("Text3")]),
12
          TableRow(children: <Widget>[Text("Text4"), Text("Text5"), Text("Text6")]),
13
          TableRow(children: <Widget>[Text("Text7"), Text("Text8"), Text("Text9")]),
14
        ],
15
        columnWidths: <int , TableColumnWidth>{
16
          0 : FractionColumnWidth(0.2),
17
          1 : FractionColumnWidth(0.4),
18
          2 : FlexColumnWidth(100),
19
        },
20
        border: TableBorder(
21
          top: BorderSide(color: Colors.red, width: 3),
22
          right: BorderSide(color: Colors.blue, width: 3),
23
          bottom: BorderSide(color: Colors.blueGrey, width: 3),
24
          left: BorderSide(color: Colors.deepPurpleAccent, width: 3),
25
          horizontalInside: BorderSide(color: Colors.deepPurpleAccent, width: 3),
26
          verticalInside: BorderSide(color: Colors.lightBlueAccent, width: 3),
27
        ),
28
        defaultVerticalAlignment: TableCellVerticalAlignment.middle,
29
      ),
30
    );
31
  }
32
}

效果如下:

20203271136

二、ListView Widget

ListView 是一个线性排列的可滚动的 Widget ,是最常用的滚动 Widget,可以横向和纵向滚动。可以通过4种方式创建 ListView ,其构造方法分别如下:

1
//默认构造方法,显示设置字Widget,适用于具有少量子Widget的ListView。因为其需要显示提供
2
//所有需要在ListView中显示的子Widget,而不是仅仅提供界面空间内可见的子Widget
3
ListView({
4
  Key key,
5
  //Axis类型可选命名参数,设置沿横轴还是纵轴滚动
6
  Axis scrollDirection = Axis.vertical,
7
  //bool类型可选命名参数,用于设置视图的滚动方向是否为读取方向
8
  bool reverse = false,
9
  //ScrollController类型可选命名参数,控制滚动视图滚动位置的控制器
10
  ScrollController controller,
11
  //bool类型可选命名参数,是否是与父PrimaryScrollController相关联的主滚动视图
12
  bool primary,
13
  //ScrollPhysics类型可选命名参数,滚动视图应如何响应用户输入
14
  ScrollPhysics physics,
15
  //boo类型可选命名参数,crollDirection中滚动视图的范围是否应由正在查看的内容确定
16
  bool shrinkWrap = false,
17
  //EdgeInsetsGeometry类型可选命名参数,内边距,使用EdgeInsets
18
  EdgeInsetsGeometry padding,
19
  //double类型可选命名参数,不为空则强制子级在滚动方向上具有给定范围
20
  this.itemExtent,
21
  //bool类型可选命名参数,是否将每个子Widget都包装在AutomaticKeepAlive组件中
22
  bool addAutomaticKeepAlives = true,
23
  //bool类型可选命名参数,是否将每个子Widget都包装在RepaintBoundary组件中
24
  bool addRepaintBoundaries = true,
25
  //bool类型可选命名参数,是否将每个子Widget都包装在IndexedSemantics组件中
26
  bool addSemanticIndexes = true,
27
  //double类型可选命名参数,用于设置不可见的缓存区域的大小
28
  double cacheExtent,
29
  //List<Widget>类型可选命名参数,用于设置滚动列表的每一项Widget
30
  List<Widget> children = const <Widget>[],
31
  //int类型可选命名参数,为ListView中的子列表中Widget提供语义信息的数量
32
  int semanticChildCount,
33
  //DragStartBehavior类型可选命名参数,确定处理拖动开始行为的方式
34
  DragStartBehavior dragStartBehavior = DragStartBehavior.start,
35
})
36
37
//此构造方法采用IndexedWidgetBuilder,可以根据需要创建子Widget。适用于有大量或无限
38
//个子Widget的ListView。其只对可见的子Widget进行构建  
39
ListView.builder({
40
  Key key,
41
  //IndexedWidgetBuilder类型必传参数,为给定索引创建Widget
42
  @required IndexedWidgetBuilder itemBuilder,
43
  //int类型可选命名参数,创建Widget的个数
44
  int itemCount,
45
  //...省略与ListView相同部分
46
})
47
48
//此构造方法采用IndexedWidgetBuilder,一个是itemBuilder,可以根据需要创建子Widget,另一个是separatorBuilder,同样构建出现在子项目之间的分隔子项目。此构造函数适用于具有固定数目的子元素的列表视图
49
ListView.separated({
50
  Key key,
51
  //IndexedWidgetBuilder类型必传参数,为给定索引创建Widget
52
  @required IndexedWidgetBuilder itemBuilder,
53
  //IndexedWidgetBuilder类型必传参数,为给定索引创建Widget分割Widget
54
  @required IndexedWidgetBuilder separatorBuilder,
55
  //int类型必传参数,创建Widget的个数
56
  @required int itemCount,
57
  //...省略与ListView相同部分
58
})
59
  
60
//此构造方法采用SliverChildDelegate,它提供了自定义模型的其他方面的功能。例如,
61
//SliverChildDelegate可以控制用于估计实际不可见的子代大小的算法  
62
const ListView.custom({
63
  Key key,
64
  //SliverChildDelegate类型必传参数,为ListView提供子Widget的委托
65
  @required this.childrenDelegate,
66
	//...省略与ListView相同部分
67
})

Axis 在上篇文章中介绍过,用于设置水平排列还是垂直排列。

reverse 用来设置视图的滚动方向是否为读取方向。例如,如果读取方向是从左到右,并且 scrollDirectionAxis.horizontal,则当 reversefalse 时,滚动视图从左向右滚动;当 reversetrue 时,从右向左滚动。如果 scrollDirectionAxis.vertical ,则当 reversefalse 时,滚动视图从顶部滚动到底部,而当 reversetrue 时,滚动视图从底部滚动到顶部。默认为 false

ScrollController 用于控制滚动视图的滚动位置和进行位置监听,当 primarytrue 时,controller 必须为空。除了可以控制滚动视图的位置外,它还可用于控制滚动视图是否应自动保存并恢复其在 PageStorage 中的滚动位置。它可用于读取当前滚动位置或更改它。

primary 用于控制在滚动视图有足够空间显示全部视图的情况下,ListView 是否可以滚动。当可用空间展示了全部视图的情况下,此属性如果为 false ,则 ListView 不可滚动,否则可以滚动。当可用空间不能完全展示全部视图的情况下,无论设置 true 还是 falseListView 都可以滚动。在 iOS 上,这还标识了滚动视图,该滚动视图将响应状态栏中的轻击而滚动到顶部。当 scrollDirectionAxis.verticalcontroller 为空时,默认值为 true

ScrollPhysics 确定可滚动小部件的物理性质,用于确定如何响应用户输入,也就是如何响应用户的操作。比如,确定用户停止拖动滚动视图后滚动视图如何继续进行动画处理。其也可以用来强制滚动视图在不可以滚动时也始终可以进行滚动,设置 physics: const AlwaysScrollableScrollPhysics() 即可。如果想强制始终不可滚动,则需设置为 physics: const ScrollPhysics()physics: NeverScrollableScrollPhysics()

shrinkWrap 用来设置 ListView 在滚动方向上的长度是否为 ListView 的所有子 Widget 所占用的最小长度。如果为 trueListView 将根据其子 Widget 列表来最小化的设置其显示范文。如果为 false ,则其将尝试将填充 ListView 的父级所提供的全部可用空间。如果滚动视图在滚动方向上没有限制约束,则 shrinkWrap 必须为 true

EdgeInsetsGeometry 主要用于设置边距,是一个抽象基类,可以使用其子类 EdgeInsets

itemExtent 如果不为空,则强制子 Widget 在滚动方向上具有给定的范围。如果纵向滚动,则强制子 Widget 具有给定的高度,如果横向滚动,则强制子 Widget 具有给定的宽度。

addAutomaticKeepAlives 是否将每个子Widget都包装在 AutomaticKeepAlive 组件中,AutomaticKeepAlive 也是一个 Widget ,功能类似于 KeepAlive ,主要作用是将子 Widget 标记为需要存活,即使该子 Widget 处于懒惰列表中也可以将其删除。但 addAutomaticKeepAlives 并没有明确配置此功能,而是用来监听子 Widget 和其他后代的 KeepAliveNotification 消息。

addRepaintBoundaries 是否将每个子Widget都包装在 RepaintBoundary 组件中 。RepaintBoundary 是一个为其子 Widget 创建单独的显示列表的 Widget 。如果子树在与树的周围部分不同的时间重新绘制,则可以提高性能。

addSemanticIndexes 是否将每个子Widget都包装在 IndexedSemantics 组件中。IndexedSemantics 是一个使用索引来注释子Widget 语义的 Widget 。

cacheExtent 视口在可见区域之前和之后都有一个区域,用于缓存当用户滚动时将变得可见的项目。属于此缓存区域的项目即使在屏幕上尚不可见,也可以进行布局。 cacheExtent 描述了缓存区域在视口的前缘和后缘之前延伸了多少像素。视口将尝试用子项覆盖的总范围是:前边缘之前的cacheExtent +主轴的范围+后边缘之后的cacheExtent。缓存区域还用于在iOS上实现隐式可访问性滚动:当可访问性焦点从可见视口中的项目移动到缓存区域中的不可见项目时,框架将通过(隐式)滚动动作将该项目显示在视图中。

semanticChildCountScrollView 的某些子类型可以自动推断此值。 例如,ListView 将使用子列表中小部件的数量,而新的 ListView.separated 构造函数将使用该数量的一半。对于 CustomScrollView 和其他未接收到构建器或小部件列表的类型,必须明确提供子计数。 如果该数字未知或无界,则应保持不变或将其设置为空。

DragStartBehavior ,传递给 DragStartDetails 的偏移量的配置,用于设置确定用户启动拖动时拖动何时正式开始。是一个枚举类型值,如下:

1
enum DragStartBehavior {
2
  //在检测到第一个下降事件的位置设置初始偏移量
3
  down,
4
  //将初始位置设置在检测到拖动开始事件的位置
5
  start,
6
}

itemBuilder 是一个 IndexedWidgetBuilder 类型,其是一个返回一个 Widget 的方法,原型为:Widget Function(BuildContext context, int index) ,功能是为给定索引创建 Widget 。

separatorBuilderitemBuilder 相同,只是在语义上不同,主要用来设置列表子 Widget 的分割 Widget 。

childrenDelegateSliverChildDelegate 类型,用于在 ListView.custom 中显示指定委托。使用 SliverChildDelegate 可以惰性的构建 ListView ,以避免创建比可视区域更多的子 Widget 。SliverChildDelegate 是一个抽象基类,需要使用其子类 SliverChildListDelegateSliverChildBuilderDelegate

SliverChildListDelegate构造方法如下:

1
//创建一个使用给定列表为子项供应子Widget的委托。
2
SliverChildListDelegate(
3
  //List<Widget>类型必传参数,要显示的Widget列表
4
  this.children, {
5
  //bool类型可选命名参数,是否将每个子Widget都包装在AutomaticKeepAlive组件中
6
  this.addAutomaticKeepAlives = true,
7
  //bool类型可选命名参数,是否将每个子Widget都包装在RepaintBoundary组件中
8
  this.addRepaintBoundaries = true,
9
  //bool类型可选命名参数,是否将每个子Widget都包装在IndexedSemantics组件中
10
  this.addSemanticIndexes = true,
11
  //SemanticIndexCallback类型可选命名参数,当addSemanticIndexes为true时使用的  
12
  //SemanticIndexCallback,默认为每个窗口小部件提供索引
13
  this.semanticIndexCallback = _kDefaultSemanticIndexCallback,
14
  //int类型可选命名参数,要添加到此小部件生成的语义索引的初始偏移量
15
  this.semanticIndexOffset = 0,
16
})

如果子级的顺序从不改变,请考虑使用常量 SliverChildListDelegate.fixed 构造函数,其创建一个恒定版本的委托,所有参数与 SliverChildListDelegate 均相同。

SliverChildBuilderDelegate 构造方法如下:

1
//按需创建子Widget的委托,惰性加载
2
const SliverChildBuilderDelegate(
3
  //IndexedWidgetBuilder类型必传参数,是一个构建器方法
4
  this.builder, {
5
  //ChildIndexGetter类型可选命名参数,在重新排序的情况下,根据子项的键来调用以查找子项的新索引
6
  this.findChildIndexCallback,
7
 //int类型可选命名参数,子Widget的数量
8
  this.childCount,
9
  //bool类型可选命名参数,是否将每个子Widget都包装在AutomaticKeepAlive组件中
10
  this.addAutomaticKeepAlives = true,
11
  //bool类型可选命名参数,是否将每个子Widget都包装在RepaintBoundary组件中
12
  this.addRepaintBoundaries = true,
13
  //bool类型可选命名参数,是否将每个子Widget都包装在IndexedSemantics组件中
14
  this.addSemanticIndexes = true,
15
  //SemanticIndexCallback类型可选命名参数,当addSemanticIndexes为true时使用的  
16
  //SemanticIndexCallback,默认为每个窗口小部件提供索引
17
  this.semanticIndexCallback = _kDefaultSemanticIndexCallback,
18
  //int类型可选命名参数,要添加到此小部件生成的语义索引的初始偏移量
19
  this.semanticIndexOffset = 0,
20
})

ListView 的使用方法如下:

1
class MyHomePage extends StatelessWidget {
2
  @override
3
  Widget build(BuildContext context) {
4
    // TODO: implement build
5
    ScrollController _lstController = ScrollController(initialScrollOffset: 610);  //初始化偏移
6
    _lstController.addListener(()=>print(_lstController.offset));  //监听输出列表偏移值
7
8
    return Scaffold(
9
      appBar: AppBar(
10
        title: Text("HomePage"),
11
      ),
12
      body: SizedBox(
13
        child: Container(
14
          color: Colors.deepPurpleAccent,
15
          child: ListView(
16
            scrollDirection: Axis.vertical,  //vertical为纵向滚动列表,horizontal为横向滚动列表
17
            padding: EdgeInsets.all(10),     //设置内边距,四周留有10像素的距离
18
//            shrinkWrap: false,             //ListView是否铺满父级的可用空间
19
            itemExtent: 600,                 //item高度
20
            controller: _lstController,
21
            children: <Widget>[
22
              Container(
23
                color: Colors.lightBlueAccent,
24
                height: 120,
25
                width: 160,
26
                child: const Center(child: Text("Text 1"),),
27
              ),
28
              Container(
29
                color: Colors.yellow,
30
                height: 120,
31
                width: 160,
32
                child: const Center(child: Text("Text 2"),),
33
              ),
34
              Container(
35
                color: Colors.red,
36
                height: 120,
37
                width: 160,
38
                child: const Center(child: Text("Text 3"),),
39
              ),
40
            ],
41
          ),
42
        ),
43
      )
44
    );
45
  }
46
}

效果如下:

2020328128

这里设置了初始化偏移一个子 Widget 的距离,所以初始化显示为第二个 Widget 在顶端。使用了监听滑动列表时列表的偏移,这里只是做了输出,如果需要对界面做更改等操作,需要使用 StatefulWidget

ListView.builder 可以按需创建子 Widget 。itemCound 如果为空,不进行设置,则会创建占满屏幕的子 Widget ,并在滑动后继续创建占满可用空间的子 Widget 。所以提供一个合理的值,可以提高 ListView 估算最大滚动范围的能力。如果要在创建 ListView 时,一次性创建所有子 Widget ,使用默认构造 ListView() 效率更高。默认情况下,ListView.builder 不支持子级重新排序。 如果您打算以后更改子顺序,请考虑使用ListViewListView.customListView.builder 使用方法如下:

1
class MyHomePage extends StatelessWidget {
2
  @override
3
  Widget build(BuildContext context) {
4
    List<Map> itemList = <Map>[
5
      {
6
        "title" : "这个是标题1",
7
        "detail" : "这是详细信息1",
8
      },
9
      {
10
      "title" : "这个是标题2",
11
      "detail" : "这是详细信息2",
12
      },
13
      {
14
      "title" : "这个是标题3",
15
      "detail" : "这是详细信息3",
16
      },
17
    ];
18
19
    return Scaffold(
20
      appBar: AppBar(
21
        title: Text("HomePage"),
22
      ),
23
      body: ListView.builder(  			//ListView.builder
24
        itemBuilder: (context, index){
25
          return Container(
26
            height: 100,
27
            padding: EdgeInsets.fromLTRB(5, 5, 5 , 0),
28
            child: Container(
29
              color: Colors.greenAccent,
30
              child: Column(
31
                crossAxisAlignment: CrossAxisAlignment.start,
32
                children: <Widget>[
33
                  Text("标题:${itemList[index]["title"]}", style: TextStyle(fontSize: 24)),
34
                  Text("详细:${itemList[index]["detail"]}", style: TextStyle(fontSize: 18))
35
                ],
36
              ),
37
            ),
38
          );
39
        },
40
        itemCount: itemList.length,
41
      ),
42
    );
43
  }
44
}

效果如下:

2020328305

ListView.separated 使用如下:

1
class MyHomePage extends StatelessWidget {
2
  @override
3
  Widget build(BuildContext context) {
4
    List<Map> itemList = <Map>[
5
      {
6
        "title" : "这个是标题1",
7
        "detail" : "这是详细信息1",
8
      },
9
      {
10
      "title" : "这个是标题2",
11
      "detail" : "这是详细信息2",
12
      },
13
      {
14
      "title" : "这个是标题3",
15
      "detail" : "这是详细信息3",
16
      },
17
    ];
18
19
    return Scaffold(
20
      appBar: AppBar(
21
        title: Text("HomePage"),
22
      ),
23
      body: Container(
24
        padding: EdgeInsets.fromLTRB(5, 5, 5 , 0),
25
        child: ListView.separated(							//ListView.separated
26
          itemBuilder: (context, index){
27
            return Container(
28
              height: 100,
29
              color: Colors.yellow,
30
              child: Column(
31
                crossAxisAlignment: CrossAxisAlignment.start,
32
                children: <Widget>[
33
                  Text("标题:${itemList[index]["title"]}", style: TextStyle(fontSize: 24)),
34
                  Text("详细:${itemList[index]["detail"]}", style: TextStyle(fontSize: 18))
35
                ],
36
              ),
37
            );
38
          },
39
          separatorBuilder: (context, index) {   //分割线
40
            return Container(
41
              height: 1,
42
              color: Colors.red,
43
            );
44
          },
45
          itemCount: itemList.length,
46
        ),
47
      ),
48
    );
49
  }
50
}

效果如下:

2020328314

ListView.custom 使用如下:

1
class MyHomePage extends StatelessWidget {
2
  @override
3
  Widget build(BuildContext context) {
4
    return Scaffold(
5
      appBar: AppBar(
6
        title: Text("HomePage"),
7
      ),
8
      body: Container(
9
        padding: EdgeInsets.fromLTRB(5, 5, 5 , 0),
10
        child: ListView.custom(								//ListView.custom
11
          childrenDelegate: SliverChildListDelegate(
12
            <Widget>[
13
              Container(
14
                color: Colors.lightBlueAccent,
15
                height: 120,
16
                width: 160,
17
                child: const Center(child: Text("Text 1"),),
18
              ),
19
              Container(
20
                color: Colors.yellow,
21
                height: 120,
22
                width: 160,
23
                child: const Center(child: Text("Text 2"),),
24
              ),
25
              Container(
26
                color: Colors.red,
27
                height: 120,
28
                width: 160,
29
                child: const Center(child: Text("Text 3"),),
30
              ),
31
            ],
32
          ),
33
        ),
34
      ),
35
    );
36
  }
37
}

实现效果与 ListView() 相同。

三、ListTile Widget

ListTile 是一个固定高度的行 Widget ,常用在 ListViewColumnDrawerCard 中。其是一个可以包含文本以及前导和后导 Widget 的 Widget。构造方法如下:

1
const ListTile({
2
  Key key,
3
  //Widget类型可选命名参数,在标题之前显示的Widget,通常为Icon或CircleAvatar
4
  this.leading,
5
  //Widget类型可选命名参数,标题Widget
6
  this.title,
7
  //Widget类型可选命名参数,标题下方显示的Widget
8
  this.subtitle,
9
  //Widget类型可选命名参数,标题后面显示的Widget,通常为Icon
10
  this.trailing,
11
  //bool类型可选命名参数,是否提供至少3行文本显示。如果为true,subtitle不能为null。
12
  //为false时,可以不提供subtitle,只显示提高行,提供则显示两行的高度并显示
13
  this.isThreeLine = false,
14
  //bool类型可选命名参数,是否密集显示
15
  this.dense,
16
  //EdgeInsetsGeometry类型可选命名参数,内边距
17
  this.contentPadding,
18
  //bool类型可选命名参数,ListTile是否可以交互
19
  this.enabled = true,
20
  //GestureTapCallback类型可选命名参数,点击操作的回调方法
21
  this.onTap,
22
  //GestureLongPressCallback类型可选命名参数,长按操作的回调方法
23
  this.onLongPress,
24
  //bool类型可选命名参数,如果还启用了此图块,则图标和文本将以相同的颜色呈现
25
  this.selected = false,
26
})

使用方法如下:

1
class MyHomePage extends StatelessWidget {
2
  @override
3
  Widget build(BuildContext context) {
4
    return Scaffold(
5
      appBar: AppBar(
6
        title: Text("HomePage"),
7
      ),
8
      body: Container(
9
        color: Colors.yellow,
10
        child: ListTile(							//ListTile
11
          leading: Icon(Icons.access_alarm),
12
          title: Text("这里显示的标题"),
13
          subtitle: Text("副标题"),
14
          trailing: Icon(Icons.add_box),
15
          isThreeLine: false,
16
          contentPadding: EdgeInsets.all(10),
17
          onTap: () => print("点击"),
18
          onLongPress: ()=> print("长按"),
19
          dense: true,
20
          selected: true,
21
        ),
22
      ),
23
    );
24
  }
25
}

效果如下:

20203281004
陌问.MW wechat
欢迎关注微信公众号,及时获取知识!