布局
基本布局
- Row(水平布局):在水平(X轴)方向上排列子widget的列表。
- Column(垂直布局):在垂直(Y轴)方向上排列子widget的列表。
- Stack(可重叠布局):可以允许其子widget简单的堆叠(Z轴)在一起。
- IndexedStack(单一显示可重叠布局):相比Stack后面编码的widget显示在Z轴上方,IndexedStack通过index可以控制显示哪个widget显示在Z轴的上方,注意,只显示一个。
- ListView(滚动列表):最常用的滚动widget。
Row
- 不带滚动属性,如果超出约束范围,在debug版本下会提示溢出。
代码
Row(crossAxisAlignment: CrossAxisAlignment.start,children: <Widget>[new Text('1'),new Text('2'),new Text('3'),],
)
常用参数
mainAxisAlignment
- X轴方向上的对齐方式
- spaceBetween:沿X轴方向均分,子widget之间的空白区域相等,两侧贴边,比如只有两个子widget就在两边,三个就左中右这样。
- spaceAround:沿X轴方向均分,左右两侧不贴边,有空白区域,但空白区域是子widget之间的空白区域的1/2。
- spaceEvenly:沿X轴方向均分,左右两侧不贴边,有空白区域,空白区域和子widget之间的空白区域大小一致。
crossAxisAlignment
- Y轴方向上的对齐方式
- stretch:让子widget充满Y轴。
- baseline:在Y轴上和基线适配,搭配textBaseline用
textBaseline
- 文本内容的基线类型,就是文本的水平边界线,注意,只有水平
- alphabetic:以字母字符底部的水平线对齐(不论中英文,都是用文字的最底部对齐)
- ideographic:以表意字符的水平线对齐。(英文如pgj这些底部会比中文矮一些)
mainAxisSize
- X轴方向应占用多少空间,默认最大化的占用主轴空间。
- 若为MainAxisSize.min,则mainAxisAlignment只能为start。
verticalDirection
- 垂直方向上的排列顺序
- up:子widget从bottom开始往top排列;
- down:子widget从top开始往bottom排列。
- 搭配crossAxisAlignment的start和end属性有如下不同:
textDirection
- 与verticalDirection类似,水平方向上的排列顺序
- ltr:left to right,从左到右排列;
- rtl:rigth to left,从右到左排列;
- 同verticalDirection类似,搭配mainAxisAlignment使用,如下:
Column
- 不带滚动属性,如果超出约束范围,在debug版本下会提示溢出。
代码
Column(crossAxisAlignment: CrossAxisAlignment.start,children: <Widget>[new Text('1'),new Text('2'),new Text('3'),],
)
常用参数
mainAxisAlignment
- Y轴方向上的对齐方式
- spaceBetween:沿Y轴方向均分,子widget之间的空白区域相等,比如只有两个子widget就在上下,三个就上中下这样。
- spaceAround:沿Y轴方向均分,上下两侧不贴边,有空白区域,但空白区域是子widget之间的空白区域的1/2。
-
- spaceEvenly:沿Y轴方向均分,上下两侧不贴边,有空白区域,空白区域和子widget之间的空白区域大小一致。
crossAxisAlignment
- X轴方向上的对齐方式
- stretch:让子widget充满X轴。
- baseline:相当于start,因为textBaseline只有水平,因为没有文字是需要人歪头90度看的。
mainAxisSize
- Y轴方向应占用多少空间,默认最大化的占用主轴空间。
- 若为MainAxisSize.min,则mainAxisAlignment只能为start。
verticalDirection
- 垂直方向上的排列顺序
- up:子widget从bottom开始往top排列;
- down:子widget从top开始往bottom排列。
- 搭配mainAxisAlignment的start和end属性有如下不同:
textDirection
- 与verticalDirection类似,水平方向上的排列顺序
- ltr:left to right,从左到右排列;
- rtl:rigth to left,从右到左排列;
- 同verticalDirection类似,搭配crossAxisAlignment使用,如下:
Stack
- 可以子widget无视位置压在另一个子widget的布局
- 内部使用Positioned定位子widget位置宽高
- width,left和right三个属性不能同时使用,必须至少有一个属性是null;
- height,top和bottom三个属性不能同时使用,必须至少有一个属性是null。
代码
Stack(alignment: Alignment(-1.0,0.0),//等价于Alignment.centerLeftchildren: <Widget>[Positioned(child: Container(width: 100.0,height: 100.0,color: Colors.red,),),Positioned(child: Container(width: 90.0,height: 90.0,color: Colors.green,),),Positioned(child: Container(width: 80.0,height: 80.0,color: Colors.blue,),),new Text('-1,0\ncenterLeft',textAlign: TextAlign.left,),],
)
完整示例
Container(width: 200,height: 200,child: Stack(children: <Widget>[Positioned(// 若是不指定位置就是(0,0)// 若是不指定size就是子view的size// top: 50.0,// left: 50.0,child: Container(width: 200,height: 200,),),Positioned(top: 0.0,left: 190.0,child: Container(width: 10.0,height: 10.0,color: Colors.green,),),],),
);
常用参数
alignment
- 可以传递AlignmentDirectional、Alignment、FractionalOffset三大类,主要用的是带方向的AlignmentDirectional。
textDirection
- 搭配AlignmentDirectional的start或者end实现类似Row的mainAxisAlignment+textDirection的效果。
fit
- loose:从Stack传递过来的约束被解除,即:
- 当Stack大小被限制为300*400,子widget元素的大小将可设置为,宽:0到300,高:0到400。
- expand:从Stack传递过来的约束被锁定到最大,即:
- 当Stack大小被限制为300*400,子widget元素的大小将锁定为,宽:300,高:400。
- passthrough:不改变子组件约束条件。和loose一致。
overflow
- 是否裁剪溢出的子widget元素
- clip:裁剪溢出部分
- visible:显示溢出部分
IndexedStack
- 相比Stack多了一个index参数,控制显示哪个子widget
- 内部使用Positioned定位子widget位置宽高
- width,left和right三个属性不能同时使用,必须至少有一个属性是null;
- height,top和bottom三个属性不能同时使用,必须至少有一个属性是null。
代码
IndexedStack(sizing: StackFit.expand,index: 1,children: <Widget>[Positioned(child: Container(width: 100.0,height: 100.0,color: Colors.red,),),Positioned(child: Container(width: 130.0,height: 90.0,color: Colors.green,),),Positioned(child: Container(width: 80.0,height: 120.0,color: Colors.blue,),),],
),
index就是children的length的区间之中的值。
比如上面的代码,就只显示index为1的子widget,也就是第二个。
常用参数
- 因为只显示一个,所以Stack的常用参数基本用不到
ListView
-
- listview需要拓展长度,比如是纵向的listview,就需要指定父view的height。
- 可以理解为可以滚动的Column。
- 有四种构造方式
- List():默认构造;
- 直接把子widget硬编码,如果子widget较多,有性能风险。
- ListView.builder();
- 不带分割线
- 懒加载,只会渲染可见的条目。
- ListView.separated;
- 带分割线
- separatorBuilder是必传参数,用于构造分割线view
- 分割线返回的是一个widget(不必一定是Divider),所以可以自定义
- ListView.custom。
- 搭配SliverChildBuilderDelegate自定义实现不同类型子widget,比如子widget和分割线交替出现等复杂场景。
- List():默认构造;
代码
/// 默认构造
ListView(children: [ new Text('1'),Divider(),new Text('2'),Divider(),new Text('3'),Divider(),],
),
/// ListView.builder()构造
final List<String> name = <String>['1','2','3',];
ListView.builder(itemCount: name.length,itemBuilder: (context, index) {return Text(name[index]);},
),
/// ListView.separated()构造
ListView.separated(itemBuilder: (context, index) {return Text(name[index]);},separatorBuilder: (context, index) {return Divider();//分割线},itemCount: name.length,
),
/// ListView.custom()
ListView.custom(childrenDelegate: SliverChildBuilderDelegate((context, index) {return Text(name[index]);},childCount: name.length,),
),
详细代码
var lv1 = ListView(//主轴滚动方向:垂直vertical,竖直horizontal ,默认为垂直vertical,scrollDirection: Axis.vertical,//是否反向 默认为false,正常顺序从起始点开始正序,true为从末尾开始排列reverse: false,//滚动控制器,默认为nullcontroller:null,//是否强制滚动(顶部或底部时是否可以滚动),默认是false,如果为true,Controller必须为nullprimary: false,//视图如何响应用户的手势滑动,有内置实现强制可以滚动 const AlwaysScrollableScrollPhysics();和强制不可以滚动const ScrollPhysics(),可忽略primary属性physics: const AlwaysScrollableScrollPhysics(),//默认为false,滚动视图在[滚动方向]中的范围是否应由正在查看的内容决定。shrinkWrap: true,//item的padding值padding: const EdgeInsets.all(10.0),//item交叉轴方向的大小,默认自适应,vertical时为高度,horizontal时为高度itemExtent: 50.0,//是否自动保存滑出屏幕外的字widget的状态,保证widget不被回收,可复用,false的手动保存。默认为trueaddAutomaticKeepAlives: true,//是否放置到重绘列表中,复杂widget可提高性能,默认为trueaddRepaintBoundaries: true,//缓存区大小,默认为250cacheExtent: 250.0,//默认构造函数中特有,直接将子widget放置内,一次性渲染完成,适合少量数据children: [new Text('测试1'),Divider(),new Text('测试2'),Divider(),new Text('测试3'),Divider(),new Text('测试4'),Divider(),new Text('测试5'),Divider(),],
);
每个item不同的listview
- 用switch-case返回不同的item来实现不同的item的view
import 'package:flutter/material.dart';class MyListPage extends StatelessWidget {final List<Item> itemList = [Item(type: ItemType.button, data: ['Button 1', 'Button 2']),Item(type: ItemType.text, data: 'Hello World'),Item(type: ItemType.image,data: 'https://example.com/images/image.jpg'),];@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('My List Page'),),body: ListView.builder(itemCount: itemList.length,itemBuilder: (BuildContext context, int index) {Item item = itemList[index];Widget itemWidget;// 根据item类型构建不同的widgetswitch (item.type) {case ItemType.button:List<String> buttonTexts = item.data;itemWidget = Row(children: [ElevatedButton(onPressed: () {},child: Text(buttonTexts[0]),),ElevatedButton(onPressed: () {},child: Text(buttonTexts[1]),),],);break;case ItemType.text:String textData = item.data;itemWidget = Text(textData);break;case ItemType.image:String imageUrl = item.data;itemWidget = Image.network(imageUrl);break;}return ListTile(title: itemWidget,);},),);}
}class Item {final ItemType type;final dynamic data;Item({required this.type,required this.data,});
}enum ItemType {button,text,image,
}
垂直滑动里嵌套水平滑动
class _PageBizCertificateState extends eState<PageBizCertificate> {final List<String> items = List.generate(20, (index) => 'Item $index');@overrideWidget pageBody(BuildContext context) {return ListView.builder(itemCount: items.length,itemBuilder: (context, index) {return MyListItem(title: items[index]);},);}Widget MyListItem({required String title}) {return Container(padding: EdgeInsets.all(16.0),child: Column(crossAxisAlignment: CrossAxisAlignment.start,children: [Text('第一行文本'),SizedBox(height: 8.0),MyHorizontalScrollList(),SizedBox(height: 8.0),Text('第三行文本'),],),);}Widget MyHorizontalScrollList() {return Container(height: 100.0,child: ListView.builder(scrollDirection: Axis.horizontal,itemCount: 10,itemBuilder: (context, index) {return Container(width: 100.0,margin: EdgeInsets.all(4.0),color: Colors.blue,child: Center(child: Text('水平项 $index'),),);},),);}}
参数列表
- scrollDirection:主轴滚动方向;默认垂直滚动Axis.vertical,还可水平滚动Axis.horizontal
- reverse:是否反向排列,默认false,即正序排列
- controller:滚动控制器,默认为null
- primary:是否强制滚动,默认false
- physics:响应用户滑动。
- NeverScrollableScrollPhysics(), // 禁止滑动
- shrinkWrap:滚动视图在滚动方向中的范围是否应由正在查看的内容决定。默认为false
- padding:距边框item边间距
- cacheExtent:缓存大小,默认250.0
- itemExtent:item在交叉轴方向上的长度;null时为自适应
- addAutomaticKeepAlives:是否自动保存滑出屏幕外的字widget的状态,默认true,保存,可复用
- addRepaintBoundaries:是否放置到重绘列表中;默认true,可提高性能
- itemBuilder:builder和separated构造函数特有要传入参数,定义item的样式
- separatorBuilder:separated构造函数特有要传入的参数,定义分割线的样式
- itemCount:列表可滚动的item数量,默认构造没有
- childrenDelegate:内部都是靠此类实现滚动和布局,但只有custom构造函数需要传入,其余都内部实现