Flutter Widget(3):多节点Widget

1.Row

线性布局,将children排成一行,主轴为水平方向,交叉轴为垂直方向。

  • textDirection:表示水平方向子widget的布局顺序是从左往右还是从右往左。
  • mainAxisSize:主轴方向的占用空间。默认是MainAxisSize.max,表示尽可能多的占用水平方向的空间,此时无论子widgets实际占用多少水平空间,Row的宽度始终等于水平方向的最大宽度;而MainAxisSize.min表示尽可能少的占用水平空间,当子widgets没有占满水平剩余空间,则Row的实际宽度等于所有子widgets占用的的水平空间;
  • mainAxisAlignment:主轴对齐方式,如果mainAxisSize值为MainAxisSize.min ,则此属性无意义,因为子widgets的宽度等于Row的宽度。只有当mainAxisSize的值为MainAxisSize.max时,此属性才有意义。textDirection是mainAxisAlignment的参考系,textDirection取值为TextDirection.ltr时,则MainAxisAlignment.start表示左对齐,textDirection取值为TextDirection.rtl时表示从右对齐。
  • crossAxisAlignment:交叉轴对齐方式,Row的高度等于子Widgets中最高的子元素高度。crossAxisAlignment的参考系是verticalDirection,即verticalDirection值为VerticalDirection.down时crossAxisAlignment.start指顶部对齐,verticalDirection值为VerticalDirection.up时,crossAxisAlignment.start指底部对齐;而crossAxisAlignment.end和crossAxisAlignment.start正好相反;
  • children :子widget数组

2.Column

Column可以在垂直方向排列其子widget。参数和Row一样,不同的是布局方向为垂直,主轴纵轴正好相反

如果Row里面嵌套Row,或者Column里面再嵌套Column,那么只有对最外面的Row或Column会占用尽可能大的空间,里面Row或Column所占用的空间为实际大小

3.Stack

可以允许其子widget简单的堆叠在一起,相当于Android中的FrameLayout,

  • alignment:此参数决定如何去对齐没有定位(没有使用Positioned)或部分定位的子widget。所谓部分定位,在这里特指没有在某一个轴上定位:left、right为横轴,top、bottom为纵轴,只要包含某个轴上的一个定位属性就算在该轴上有定位。
  • textDirection:决定alignment对齐的参考系即:textDirection的值为TextDirection.ltr,则alignment的start代表左,end代表右;textDirection的值为TextDirection.rtl,则alignment的start代表右,end代表左。
  • fit:此参数用于决定没有定位的子widget如何去适应Stack的大小。StackFit.loose表示使用子widget的大小,StackFit.expand表示扩伸到Stack的大小,passthrough不改变子widget的约束条件。
  • overflow:此属性决定如何显示超出Stack显示空间的子widget,值为Overflow.clip时,超出部分会被剪裁(隐藏),值为Overflow.visible 时则不会。

Positioned

const Positioned({
  Key key,
  this.left, 
  this.top,
  this.right,
  this.bottom,
  this.width,
  this.height,
  @required Widget child,
})

left、top 、right、 bottom分别代表离Stack左、上、右、底四边的距离。width和height用于指定定位元素的宽度和高度,注意,此处的width、height 和其它地方的意义稍微有点区别,此处用于配合left、top 、right、 bottom来定位widget,举个例子,在水平方向时,你只能指定left、right、width三个属性中的两个,如指定left和width后,right会自动算出(left+width),如果同时指定三个属性则会报错,垂直方向同理。

4.IndexedStack

IndexedStack继承自Stack,它的作用是显示第index个child,其他child都是不可见的。所以IndexedStack的尺寸永远是跟最大的子节点尺寸一致。

5.Wrap

子Widget超出屏幕范围会自动换行,Wrap的很多属性在Row(包括Flex和Column)中也有,如direction、crossAxisAlignment、textDirection、verticalDirection等

  • direction:主轴(mainAxis)的方向,默认为水平。
  • alignment:主轴方向上的对齐方式,默认为start。
  • spacing:主轴方向子widget的间距
  • runSpacing:纵轴方向的间距
  • runAlignment:纵轴方向的对齐方式

6.Flow

一个实现流式布局算法的widget,使用比较复杂,一般多实用Wrap

7.Table

为其子widget使用表格布局算法的widget,

Table({
  Key key,
  this.children = const [],
  this.columnWidths,
  this.defaultColumnWidth = const FlexColumnWidth(1.0),
  this.textDirection,
  this.border,
  this.defaultVerticalAlignment = TableCellVerticalAlignment.top,
  this.textBaseline,
})
  • columnWidths:设置每一列的宽度。
  • defaultColumnWidth:默认的每一列宽度值,默认情况下均分。
  • textDirection:文字方向
  • border:表格边框。
  • defaultVerticalAlignment:每一个cell的垂直方向的alignment。
    总共包含5种:
    top:被放置在的顶部;
    middle:垂直居中;
    bottom:放置在底部;
    baseline:文本baseline对齐;
    fill:充满整个cell。
  • textBaseline:defaultVerticalAlignment为baseline的时候,会用到这个属性。

8.ListView

ListView是最常用的可滚动widget,它可以沿一个方向线性排布所有子widget。

  • itemExtent:该参数如果不为null,则会强制children的"长度"为itemExtent的值;这里的"长度"是指滚动方向上子widget的长度,即如果滚动方向是垂直方向,则itemExtent代表子widget的高度,如果滚动方向为水平方向,则itemExtent代表子widget的长度。在ListView中,指定itemExtent比让子widget自己决定自身长度会更高效,这是因为指定itemExtent后,滚动系统可以提前知道列表的长度,而不是总是动态去计算,尤其是在滚动位置频繁变化时(滚动系统需要频繁去计算列表高度)。
  • shrinkWrap:该属性表示是否根据子widget的总长度来设置ListView的长度,默认值为false 。默认情况下,ListView的会在滚动方向尽可能多的占用空间。当ListView在一个无边界(滚动方向上)的容器中时,shrinkWrap必须为true。
  • addAutomaticKeepAlives:该属性表示是否将列表项(子widget)包裹在AutomaticKeepAlive widget中;典型地,在一个懒加载列表中,如果将列表项包裹在AutomaticKeepAlive中,在该列表项滑出视口时该列表项不会被GC,它会使用KeepAliveNotification来保存其状态。如果列表项自己维护其KeepAlive状态,那么此参数必须置为false。
  • addRepaintBoundaries:该属性表示是否将列表项(子widget)包裹在RepaintBoundary中。当可滚动widget滚动时,将列表项包裹在RepaintBoundary中可以避免列表项重绘,但是当列表项重绘的开销非常小(如一个颜色块,或者一个较短的文本)时,不添加RepaintBoundary反而会更高效。和addAutomaticKeepAlive一样,如果列表项自己维护其KeepAlive状态,那么此参数必须置为false。

默认构造函数

ListView(
  shrinkWrap: true,
  padding: EdgeInsets.all(20.0),
  children: [
    Text('I\'m dedicating every day to you'),
    Text('Domestic life was never quite my style'),
    Text('When you smile, you knock me out, I fall apart'),
    Text('And I thought I was so smart'),
  ],
)

ListView.builder

ListView.builder(
  itemCount: 1000,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text("$index"),
    );
  },
)

ListView.separated

class ListView3 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //下划线widget预定义以供复用。  
    Widget divider1=Divider(color: Colors.blue,);
    Widget divider2=Divider(color: Colors.green);
    return ListView.separated(
        itemCount: 100,
        //列表项构造器
        itemBuilder: (BuildContext context, int index) {
          return ListTile(title: Text("$index"));
        },
        //分割器构造器
        separatorBuilder: (BuildContext context, int index) {
          return index%2==0?divider1:divider2;
        },
    );
  }
}

9.GridView

一个滚动的多列列表

默认构造函数

GridView({
  Axis scrollDirection = Axis.vertical,
  bool reverse = false,
  ScrollController controller,
  bool primary,
  ScrollPhysics physics,
  bool shrinkWrap = false,
  EdgeInsetsGeometry padding,
  @required SliverGridDelegate gridDelegate, //控制子widget layout的委托
  bool addAutomaticKeepAlives = true,
  bool addRepaintBoundaries = true,
  double cacheExtent,
  List children = const [],
})
  • scrollDirection:滚动的方向,有垂直和水平两种,默认为垂直方向(Axis.vertical)。
  • reverse:默认是从上或者左向下或者右滚动的,这个属性控制是否反向,默认值为false,不反向滚动。
  • controller:控制child滚动时候的位置。
  • primary:是否是与父节点的PrimaryScrollController所关联的主滚动视图。
  • physics:滚动的视图如何响应用户的输入。
  • shrinkWrap:滚动方向的滚动视图内容是否应该由正在查看的内容所决定。
  • padding:四周的空白区域。
  • cacheExtent:缓存区域。
  • gridDelegate:控制GridView中子节点布局的delegate。

gridDelegate参数,类型是SliverGridDelegate,它的作用是控制GridView子widget如何排列(layout),SliverGridDelegate是一个抽象类,定义了GridView Layout相关接口,子类需要通过实现它们来实现具体的布局算法,Flutter中提供了两个SliverGridDelegate的子类SliverGridDelegateWithFixedCrossAxisCount和SliverGridDelegateWithMaxCrossAxisExtent

SliverGridDelegateWithFixedCrossAxisCount

该类通过确定横轴子widget的数量和宽高比从而确定了子widget的最大限时空间

SliverGridDelegateWithFixedCrossAxisCount({
  @required double crossAxisCount, 
  double mainAxisSpacing = 0.0,
  double crossAxisSpacing = 0.0,
  double childAspectRatio = 1.0,
})
  • crossAxisCount:横轴子元素的数量。此属性值确定后子元素在横轴的长度就确定了,即ViewPort横轴长度/crossAxisCount。
  • mainAxisSpacing:主轴方向的间距。
  • crossAxisSpacing:横轴方向子元素的间距。
  • childAspectRatio:子元素在横轴长度和主轴长度的比例。由于crossAxisCount指定后子元素横轴长度就确定了,然后通过此参数值就可以确定子元素在主轴的长度。

SliverGridDelegateWithMaxCrossAxisExtent

该类通过确定子widget在交叉轴的最大长度和宽高比从而确定了子widget的最大限时空间

SliverGridDelegateWithMaxCrossAxisExtent({
  double maxCrossAxisExtent,
  double mainAxisSpacing = 0.0,
  double crossAxisSpacing = 0.0,
  double childAspectRatio = 1.0,
})
  • maxCrossAxisExtent:子widget在交叉轴的最大长度,因为每个子元素的长度仍然是等分的,所以会按照设置的长度计算出能展示的数量然后算出长度的最大值,当maxCrossAxisExtent的值在区间(450/4,450/3]内的话,子元素最终实际长度都为150

GridView.count

GridView.count构造函数内部使用了SliverGridDelegateWithFixedCrossAxisCount,我们通过它可以快速的创建横轴固定数量子元素的GridView

GridView.count( 
  crossAxisCount: 3,
  childAspectRatio: 1.0,
  children: [
    Icon(Icons.ac_unit),
    Icon(Icons.airport_shuttle),
    Icon(Icons.all_inclusive),
    Icon(Icons.beach_access),
    Icon(Icons.cake),
    Icon(Icons.free_breakfast),
  ],
);

GridView.extent

GridView.extent构造函数内部使用了SliverGridDelegateWithMaxCrossAxisExtent,我们通过它可以快速的创建纵轴子元素为固定最大长度的的GridView

GridView.extent(
   maxCrossAxisExtent: 120.0,
   childAspectRatio: 2.0,
   children: [
     Icon(Icons.ac_unit),
     Icon(Icons.airport_shuttle),
     Icon(Icons.all_inclusive),
     Icon(Icons.beach_access),
     Icon(Icons.cake),
     Icon(Icons.free_breakfast),
   ],
 );

GridView.builder

上面我们介绍的GridView都需要一个Widget数组作为其子元素,这些方式都会提前将所有子widget都构建好,所以只适用于子Widget数量比较少时,当子widget比较多时,我们可以通过GridView.builder来动态创建子Widget。

GridView.builder 必须指定的参数有两个:

GridView.builder(
 ...
 @required SliverGridDelegate gridDelegate, 
 @required IndexedWidgetBuilder itemBuilder,
)

你可能感兴趣的:(Flutter Widget(3):多节点Widget)