基础组件
Text
Text 是文本控件,类似于 Android 中 TextView。Text的常用属性如下图所示:
代码示例如下:
Text(' Flutter是谷歌推出的移动端跨平台开发框架,使用的编程语言是Dart',
maxLines: 2,
overflow:TextOverflow.ellipsis ,
style: TextStyle(
color: Colors.red,
fontSize: 32,
decoration:TextDecoration.underline
),
),
SelectableText
上面介绍的 Text 是无法选择复制的,如果我们需要支持选择复制的功能,这时我们就需要将 Text 改变成 SelectableText。代码示例如下:
SelectableText(
"Text - ZeroFlutter",
style: TextStyle(
// 颜色蓝色
color: Colors.blue,
// 字号 24
fontSize: 24,
),
)
Button
Flutter 没有直接给出 Button 组件,而是提供了各种样式的 Button 组件。常用的 Button 组件有:
- RaisedButton:RaisedButton是中规中矩的按钮,点击的时候会带一点波纹以及阴影效果
- FlatButton:FlatButton意为平滑的按钮,所以它非常简洁、扁平,没有背景也没有边框
- IconButton:IconButton 是一个图标控件的按钮,没有背景,没有文字,只有一个图标
- OutlineButton:OutlineButton是一个带有边框的按钮,但是它也没有背景,点击OutlineButton,边框和背景颜色才会呈高亮显示。
- FloatingActionButton:悬浮的按钮,专用于分享和导航等需求
代码示例如下:
RaisedButton(
child: Text('RaisedButton'),
color: Colors.blue,
textColor: Colors.red,
onPressed: ()=>{},
),
FlatButton(
child: Text('FlatButton'),
textColor: Colors.red,
onPressed: ()=>{},
),
IconButton(
icon: Icon(Icons.close),
onPressed: ()=>{},
),
OutlineButton(
child: Text('OutlineButton'),
color: Colors.blue,
textColor: Colors.red,
onPressed: ()=>{},
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: ()=>{},
tooltip: '你点击的是FloatingActionButton',
),
如果 Button 组件无法满足需求,可以使用 shape 属性来设置按钮的形状,代码示例如下:
OutlineButton(
child: Text("我是自定义按钮"),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),
),
Icon
Icon 是图标组件,通常使用系统内置的图标。代码示例如下:
Icon(
Icons.favorite,
size: 48,
color: Colors.red,
)
Image
Image 组件可以加载和显示各种类型的图像,包括网络图片、本地图片等。代码示例如下:
// 加载本地图片
Image(
image: AssetImage("images/press.jpg"),
width: 500,
)
// 加载网络图片
Image(
image: NetworkImage(""),
width: 200,
),
// 加载手机图片
Image.file(
File('/storage/emulated/0/Download/one.jpg'),
width: 200,
),
需要注意,加载本地图片必须在 pubspec.yaml 文件中配置本地图片的位置。代码示例如下:
flutter:
assets:
- images/press.jpg
常用的 Iamge 属性如下图所示:
fit 属性主要用于 Image 组件,用于控制图像在 Image 组件中的缩放和裁剪方式。有三种,分别是:
BoxFit.fill:将图像拉伸或压缩以填充整个Image组件的边界,不保持图像的原始宽高比。BoxFit.contain:将图像等比例缩放,使图像能够完整地显示在Image组件的边界内,并且尽可能地占据最大空间,可能会留下空白区域。BoxFit.cover:将图像等比例缩放,使图像能够完全覆盖Image组件的边界,可能会裁剪掉部分图像。
FlutterLogo
是一个显示 Flutter logo 的组件,一般用于开发时占位。代码示例如下:
FlutterLogo(
size:100.0,
color:Colors.blue,
),
TextField
TextField 是文本框组件。代码示例如下:
TextEditingController userController=new TextEditingController();
TextEditingController passwordController=new TextEditingController();
body: Center(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.all(10),
child: TextField(
controller: _userController,
autofocus: false,
decoration: InputDecoration(
labelText: '请输入邮箱地址',
icon: Icon(Icons.email),
errorText: '邮箱地址输入错误',
),
keyboardType: TextInputType.emailAddress,
readOnly: false,
maxLines: 1,
minLines: 1,
onChanged: (String text){
print(text);
},
onSubmitted: (String text){
print('你在文本框中输入了'+text);
},
cursorWidth: 10,
cursorColor: Colors.red,
cursorRadius: Radius.circular(5),
),
),
],
),
),
TextField 的属性如下图所示:
TextFormField
TextFormField 基于TextField组件封装了一层,能够做到数据的前置校验,也能够设置其默认值。代码示例如下:
TextFormField(
decoration: InputDecoration(
labelText: '密码',
),
initialValue: '23365+989+8+98',
obscureText: true,
validator: (value) {
if (value.isEmpty) {
return '请输入密码';
}
return null;
},
),
TextField 和 TextFormField 都是通过 TextEditingController 来操作内部的文本内容的
单一子元素组件(single-child)
单一子元素(single-child)组件,顾名思义就是只能包含一个子组件的组件,常见的有 Container、Padding、Align、Center、FittedBox、AspectRatio、SingleChildScrollView、FractionallySizedBox、ConstrainedBox和Baseline等。下面分别介绍。
Container
Container 是最常用的单一子元素(single-child)组件。代码示例如下
Container(
// 设置子组件的位置为居中
alignment: Alignment.center,
// 默认 Container 是占据整个屏幕的,constraints 属性可以控制 Container 的大小
constraints: BoxConstraints.expand(width: 100,height: 80),
//装饰器
decoration: BoxDecoration(
// 边框:黄色、大小为5的实线边框
border: Border.all(color: Colors.yellowAccent, style: BorderStyle.solid, width: 5),
// 背景图
image: new DecorationImage(
image: AssetImage('images/phone.jpg'),
),
// 边框圆角
borderRadius: BorderRadius.all(Radius.circular(30)),
//阴影效果
boxShadow: [
BoxShadow(
color: Colors.redAccent,//阴影颜色
offset: Offset(20, 20),//阴影相偏移量
blurRadius: 10,//高斯模糊数值
),
],
),
//设置旋转角度
transform: Matrix4.rotationZ(.3),
child: Text(''),
),
Padding
Padding 用于设置内边距。代码示例如下:
Container(
width: 200.0,
height: 200.0,
color: Colors.blue,
child: Padding(
child: Text('我是文本'),
padding: const EdgeInsets.all(10.0),
),
),
Padding的布局分为以下两种情况。
- child为空时:产生一个宽为left + right、高为top + bottom的区域。
- child不为空时:Padding会将布局约束传递给child,根据设置的padding属性,缩小child的布局尺寸;然后Padding将自己调整到child设置了padding属性的尺寸,在child周围创建空白区域。
EdgeInsets 是用于填充各个方向的空白像素,有三种,分别是:
- EdgeInsets.symmetric:用于设置对称方向的填充,vertical指top和bottom,horizontal指left和right
- EdgeInsets.fromLTRB:分别指定4个方向的填充
- EdgeInsets.All: 所有方向均使用相同数值的填充
Align
Align 用于设置其对齐方式,例如居中、居左、居右等。Align 有两个常用的属性——widthFactor与heightFactor。当Align不设置widthFactor与heightFactor属性的时候,Align只会跟随alignment属性调整其位置。当Align设置这两个属性后,Align会随着这两个属性改变自己的尺寸。代码示例如下:
new Align(
child: Text('我是一个Align'),
heightFactor: 2.0,
alignment: Alignment.center,
),
Center
Center 组件继承自 Align,表示一个居中的组件。代码示例如下:
new Center(
child: Text('我是一个Align'),
heightFactor: 2.0,
),
FittedBox
FittedBox 是用于给子组件三种缩放方式的组件。其类似于 Android ImageView 的 scaleType 属性。代码示例如下:
new Column(
children: <Widget>[
Container(
width: 100.0,
height: 100.0,
color: Colors.blue,
child: FittedBox(
child: Text('BoxFit.contain',style: TextStyle(fontSize: 32),),
fit: BoxFit.contain,
),
),
Container(
width: 100.0,
height: 100.0,
color: Colors.red,
child: FittedBox(
child: Text('BoxFit.cover',style: TextStyle(fontSize: 32),),
fit: BoxFit.cover,
),
),
Container(
width: 100.0,
height: 100.0,
color: Colors.yellow,
child: FittedBox(
child: Text('BoxFit.fill',style: TextStyle(fontSize: 32),),
fit: BoxFit.fill,
),
),
Container(
width: 100.0,
height: 100.0,
color: Colors.orange,
child: FittedBox(
child: Text('BoxFit.scaleDown',style: TextStyle(fontSize: 32),),
fit: BoxFit.scaleDown,
),
),
Container(
width: 100.0,
height: 100.0,
color: Colors.indigo,
child: FittedBox(
child: Text('BoxFit.fitHeight',style: TextStyle(fontSize: 32),),
fit: BoxFit.fitHeight,
),
),
],
),
AspectRatio
AspectRatio的作用是根据设置调整子组件 child 的宽高比。代码示例如下:
new Container(
width: 200.0,
color: Colors.blue,
child: AspectRatio(
// aspectRatio 子组件表示宽高比
aspectRatio: 2.0/1.0,
child: Container(
color: Colors.yellow,
),
),
),
SingleChildScrollView
SingleChildScrollView 的作用是一个只能嵌套一个组件的滚动布局。虽然SingleChildScrollView只能有一个子组件,但是其子组件可以是一个多元素组件。代码示例如下:
new SingleChildScrollView(
child:Column(
children: <Widget>[...其他子组件],
)
),
SingleChildScrollView 默认滚动方向是垂直的,可以通过 scrollDirection属性设置为 scrollDirection属性设置为 Axis.horizontal 改成水平滚动。也可以根据reverse属性设置阅读顺序。
FractionallySizedBox
FractionallySizedBox的用途是基于宽度缩放因子和高度缩放因子来调整布局大小,和FittedBox一样,子组件都有可能超出父组件设置的范围。代码示例如下:
Container(
color: Colors.yellow,
height: 50.0,
width: 50.0,
child: FractionallySizedBox(
alignment: Alignment.topLeft,
widthFactor: 2.0,
heightFactor: 1.0,
child: new Container(
width: 200.0,//(1)
color: Colors.blue,
),
),
),
ConstrainedBox
ConstrainedBox是一种有约束性的组件。例如,子组件无论如何都不能超出设置的约定范围。代码示例如下:
ConstrainedBox(
constraints: BoxConstraints(
minWidth: 100.0,
minHeight: 100.0,
maxWidth: 200.0,
maxHeight: 200.0,
),
child: Container(
color: Colors.blue,
width: 100.0,
height: 50.0,
),
),
ConstrainedBox组件必须设置其constraints属性值,如果不设置的话,虽然编译器不会报错,但是运行之后,App会崩溃并提示错误
Baseline
Baseline是一个基线组件,它可以把不相关的几个组件设置在同一条水平线上进行对齐。代码示例如下:
body:new Row(
children: <Widget>[
Baseline(
child: FlutterLogo(
size: 100.0,
colors: Colors.yellow,
),
baseline: 100.0,
baselineType: TextBaseline.alphabetic,
),
Baseline(
child: FlutterLogo(
size: 100.0,
colors: Colors.blue,
),
baseline: 100.0,
baselineType: TextBaseline.alphabetic,
),
Baseline(
child: FlutterLogo(
size: 100.0,
colors: Colors.indigo,
),
baseline: 100.0,
baselineType: TextBaseline.alphabetic,
),
],
),
Drawer
Drawer 是侧滑菜单组件。代码示例如下:
//main.dart文件
import 'package:flutter/material.dart';
import 'onePage.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
routes: {
'/page1':(context)=>RightPage("我的主页",),
'/page2':(context)=>RightPage("我的相册",),
'/page3':(context)=>RightPage("我的文件",),
'/page4':(context)=>RightPage("我的游戏",),
},
home: DrawerDemo(title: '侧滑菜单'),
);
}
}
class DrawerDemo extends StatefulWidget {
DrawerDemo({Key key, this.title}) : super(key: key);
final String title;
@override
_DrawerDemoState createState() => _DrawerDemoState();
}
class _DrawerDemoState extends State<DrawerDemo> {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('侧滑菜单'),
),
drawer: Drawer(
child: ListView(
children: <Widget>[
UserAccountsDrawerHeader(
accountName: Text('liyuanjinglyj'),
accountEmail: Text('liyuanjinglyj@163.com'),
currentAccountPicture: GestureDetector(
child: new CircleAvatar(
backgroundImage: AssetImage('images/header.png'),
)
),
decoration: BoxDecoration(
color: Colors.blue,
),
),
ListTile(
title: Text('我的主页'),
leading: Icon(Icons.description),
trailing: Icon(Icons.arrow_forward_ios),
onTap: (){
Navigator.pushNamed(context, "/page1");
},
),
ListTile(
title: Text('我的相册'),
leading: Icon(Icons.image),
trailing: Icon(Icons.arrow_forward_ios),
onTap: (){
Navigator.pushNamed(context, "/page2");
},
),
ListTile(
title: Text('我的文件'),
leading: Icon(Icons.insert_drive_file),
trailing: Icon(Icons.arrow_forward_ios),
onTap: (){
Navigator.pushNamed(context, "/page3");
},
),
new Divider(),//分割线
ListTile(
title: Text('我的游戏'),
leading: Icon(Icons.videogame_asset),
trailing: Icon(Icons.arrow_forward_ios),
onTap: (){
Navigator.pushNamed(context, "/page4");
},
),
],
),
),
body:Center(
child: Text('主页面',style: TextStyle(fontSize: 50),),
),
);
}
}
//onePage.dart文件
import 'package:flutter/material.dart';
class RightPage extends StatelessWidget {
final String title;
RightPage(this.title);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this.title),
),
body: Center(
child: Text(this.title,style: TextStyle(fontSize: 50),),
),
);
}
}
Swiper
Swiper 是用于轮播广告或者资讯的组件。但是 Swiper组件并不是官方提供的,所以我们需要引入这个组件。Flutter 提供的是 PageView,但是这个使用比较复杂。代码示例如下:
引入组件:
dependencies:
flutter_swiper: ^1.1.6
实现轮播效果:
body:Container(
height: 200,
child: Swiper(
scrollDirection: Axis.horizontal,//设置横向
itemCount: 4,//数量为4
autoplay: true,//自动翻页
itemBuilder: (BuildContext context,int index){
return Image.network(imgLists[index]);//返回图片
},
pagination: SwiperPagination(//创建圆形分页指示
alignment: Alignment.bottomCenter,//分页指示位置底部中间
margin: const EdgeInsets.fromLTRB(0, 0, 20, 10),//间距
builder: DotSwiperPaginationBuilder(//圆形,选中为白色圆点,没选中为黑色圆点
color: Colors.black54,
activeColor: Colors.white
),
),
),
),
SliverPersistentHeaderDelegate
SliverPersistentHeaderDelegate 用于实现自定义折叠的效果。代码示例如下:
class MySliverPersistentHeaderDelegate implements SliverPersistentHeaderDelegate{
@override
//折叠前大小
double maxExtent;
@override
//折叠后大小
double minExtent;
MySliverPersistentHeaderDelegate({this.maxExtent,this.minExtent});
@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
return Stack(
fit: StackFit.expand,//大小与父组件一样
children: <Widget>[
Image.asset(
'images/phone.jpg',
fit: BoxFit.cover,//尽可能小,同时覆盖整个目标
),
Positioned(//层叠组件
left: 20,
bottom: 20,
right: 20,
child: Text(
'我的相册',
style: TextStyle(
fontSize: 30,
color: Colors.red
),
),
),
],
);
}
@override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
return true;
}
@override
// TODO: implement snapConfiguration
FloatingHeaderSnapConfiguration get snapConfiguration => null;
@override
// TODO: implement stretchConfiguration
OverScrollHeaderStretchConfiguration get stretchConfiguration => null;
}
多子元素组件
多子元素(multi-child)组件,顾名思义就是可以包含多个子组件的组件。其中常用的有:Scaffold、AppBar、Row、Column、ListView、GridView、CustomScrollView、CustomMultiChildLayout、stack、IndexedStack、Table、Flex、Wrap、Flow等。下面一一介绍:
Scaffold
Scaffold(脚手架),是基于 Material Design 可视化布局的结构,也是Flutter提供的标准化布局容器。它集成了AppBar(顶部导航栏)、body(界面内容)、bottomNavigationBar(底部菜单)、floatingActionButton(右下角按钮)以及drawer(侧滑菜单)。Scaffold 的结构如下:
Return Scaffold(
AppBar://...
body://...
bottomNavigationBar://...
floatingActionButton://...
drawer://...
);
AppBar
AppBar是顶部导航栏,它的结构如下图所示:
使用示例如下:
home: new Scaffold(
appBar: new AppBar(
leading: IconButton(
icon: Icon(Icons.add_to_photos),
onPressed: ()=>{},
),
title: new Text('AppBar'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
tooltip: '添加',
onPressed: ()=>{},
),
IconButton(
icon: Icon(Icons.delete),
tooltip: '删除',
onPressed: ()=>{},
),
IconButton(
icon: Icon(Icons.search),
tooltip: '查询',
onPressed: ()=>{},
),
],
),
),
一般来说,在Flutter开发中,actions最多放3个
Row和Column
Row和Column属于线性布局组件。其中Row是行多子元素组件,Column是列多子元素组件。它们的属性都是类似的,这里以 Row 为例,代码示例如下:
body: new Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,//(1)
crossAxisAlignment: CrossAxisAlignment.stretch,//(2)
mainAxisSize: MainAxisSize.min,//(3)
textDirection: TextDirection.rtl,//(4)
children: <Widget>[
Container(
width: 100.0,
height: 100.0,
color: Colors.yellow,
alignment: Alignment.center,
child: Text('1',style: TextStyle(fontSize: 20),),
),
Container(
width: 100.0,
height: 100.0,
color: Colors.deepOrange,
alignment: Alignment.center,
child: Text('2',style: TextStyle(fontSize: 20),),
),
Container(
width: 100.0,
height: 100.0,
color: Colors.green,
alignment: Alignment.center,
child: Text('3',style: TextStyle(fontSize: 20),),
),
],
),
常见的Row的属性如下图所示:
ListView
Flutter中的ListView与Android开发中的ListView、RecycleView有些类似,都是线性列表组件。代码示例如下:
// 创建 ListView 的方式一
ListView(
itemExtent:30.0, // 子组件的高度范围
children:<widget>[
Text('1'),
Text('2'),
Text('3'),
Text('4'),
]
),
// 方式二
ListView.builder(
itemExtent:30.0,
itemCount:4, // 如果不设置,那么列表是无限的
itemBuilder:(context,position){
return Text('$position');
}
),
// 方式三,separated 方法创建的列表可以加上分割符
ListView.separated(
itemBuilder:(context,position){
return Text('$position');
}
separatorBuilder:(context,position){
return Container(
width:500,
height:20,
color:Colors.red,
);
}
itemCount:10,
),
如果想要实现自定义的功能,可以使用 ListView.custom
GridView
GridView 是实现网格结构列表的组件。代码示例如下:
body: GridView.count(
crossAxisCount: 2,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
children: <Widget>[
Container(
width: 200,
height: 200,
color: Colors.yellow,
),
//省略N个Container
],
),
body: GridView.extent(
maxCrossAxisExtent: 130.0,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
children: <Widget>[
Container(
width: 200,
height: 200,
color: Colors.yellow,
),
],
),
CustomScrollView
CustomScrollView是可以包裹ListView与GridView的集合组件。主要用于,单个界面并不包含一个滚动列表组件时。代码示例如下:
body: CustomScrollView(
slivers: <Widget>[
SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
childAspectRatio: 4
),
delegate: SliverChildBuilderDelegate((BuildContext context,int index){
return Container(
alignment: Alignment.center,
color: Color.fromARGB(255, 255-index*6, 255-index*20, index*20),
child: Text('gridview$index'),
);
},childCount: 10),
),
SliverFixedExtentList(
itemExtent: 50,
delegate: SliverChildBuilderDelegate((BuildContext context,int index){
return Container(
alignment: Alignment.center,
color: Colors.teal[100*(index%5)],
child: Text('listview$index'),
);
}),
),
],
),
CustomMultiChildLayout
CustomMultiChildLayout是一个多节点、自定义布局组件,通过提供的delegate可以实现控制节点的位置以及尺寸,其具体的布局行为如下:
- 可以决定每个子节点的位置;
- 可以决定每个子节点的布局约束;
- 可以决定自身的尺寸,而且自身的尺寸不依赖子节点的尺寸。
代码示例如下:
class _MyLayoutDelegate extends MultiChildLayoutDelegate{
static const String layoutTitle='layout_bar';
static const String body='body';
//布局规则
@override
void performLayout(Size size) {
//布局layout,并返回它的大小,方便后续放body组件
Size layoutSize=layoutChild(layoutTitle ,new BoxConstraints(maxHeight: size.
height,maxWidth: size.width));
//将layoutTitle放在顶部(0.0,0.0)处
positionChild(layoutTitle, Offset(0.0,0.0));
//布局body,约束为剩下的空间
layoutChild(body, BoxConstraints.tight(Size(size.width,size.height)));
//将body放在距离layoutTitle下方layoutSize.height处
positionChild(body, Offset(0.0,layoutSize.height));
}
//是否需要重新布局
@override
bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) {
return false;
}
}
body: CustomMultiChildLayout(
delegate: _MyLayoutDelegate(),
children: <Widget>[
LayoutId(
id: _MyLayoutDelegate.layoutTitle,
child: Text('这是Title'),
),
LayoutId(
id: _MyLayoutDelegate.body,
child: Text('这是body'),
),
],
),
Stack
Stack 是一个绝对布局的组件。代码示例如下:
body:Center(
child: Stack(
alignment: Alignment(0.1,1),
children: <Widget>[
CircleAvatar(
backgroundImage: AssetImage('images/press.jpg'),
radius: 100,
),
Container(
decoration: BoxDecoration(
color: Colors.black45,
),
child: Text(
'人民邮电出版社',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white
),
),
),
],
),
),
IndexedStack
IndexedStack继承Stack,通过IndexedStack的index属性,可以直接切换它的子组件。代码示例如下:
body:Center(
child: IndexedStack(
index: 2,
alignment: Alignment.center,
children: <Widget>[
Text("第一层"),
Text("第二层"),
Text("第三层"),
],
),
),
Table
Table是一个表格组件。Table组件通过TableRow子属性逐行设置数据,同时通过columnWidths属性设置列宽,通过border属性设置表格边框样式等。代码示例如下:
body:Center(
child: Table(
columnWidths: const {
0: FixedColumnWidth(100.0),
1: FixedColumnWidth(200.0),
2: FixedColumnWidth(50.0),
},
border: TableBorder.all(
color: Colors.blue,
width: 2,
style: BorderStyle.solid
),
children: [
TableRow(
decoration: BoxDecoration(
color: Colors.yellow
),
children: [
Text('姓名'),
Text('职业'),
Text('年龄'),
],
),
TableRow(
decoration: BoxDecoration(
color: Colors.yellow
),
children: [
Text('张三'),
Text('产品经理'),
Text('30'),
],
),
TableRow(
decoration: BoxDecoration(
color: Colors.yellow
),
children: [
Text('李四'),
Text('软件工程师'),
Text('27'),
],
),
TableRow(
decoration: BoxDecoration(
color: Colors.yellow
),
children: [
Text('王五'),
Text('执行总裁'),
Text('55'),
],
),
],
),
),
Flex
Flex 借鉴了前端的Flex布局方式,代码示例如下:
body:Column(
children: <Widget>[
Container(
height: 200,
child: Flex(
direction: Axis.horizontal,
children: <Widget>[
Expanded(
flex: 1,
child: Container(
color: Colors.yellow,
),
),
Expanded(
flex: 2,
child: Container(
color: Colors.blue,
),
),
],
),
),
],
),
Wrap
Wrap组件能代替Row组件,当一行显示不全的时候,会自动进行换行处理。代码示例如下:
body:Wrap(
spacing: 10,
runSpacing: 1,
children: <Widget>[
FlatButton(
child: Text('Flutter技术开发'),
),
FlatButton(
child: Text('Python'),
),
FlatButton(
child: Text('Vue'),
),FlatButton(
child: Text('Android Studio'),
),
FlatButton(
child: Text('Django'),
),
FlatButton(
child: Text('C/C++'),
),
FlatButton(
child: Text('Qt5'),
),
FlatButton(
child: Text('Weex'),
),
],
),
Wrap的属性如下图所示:
Flow
代码示例如下:
class NightFlowDelegate extends FlowDelegate{
EdgeInsets margin=EdgeInsets.zero;//默认为0
NightFlowDelegate({this.margin});
@override
void paintChildren(FlowPaintingContext context) {
var left=margin.left;
var top=margin.top;
for(int i=0;i<context.childCount;i++){
var childWidth=context.getChildSize(i).width+left+margin.right;//子组件的长度
if(childWidth<context.size.width){
context.paintChild(
i,
transform: new Matrix4.compose(Vector.Vector3(left,top,0.0),
Vector.Quaternion(0.0,0.0,0.0,0.0), Vector.Vector3(1.0,1.0,1.0)));
left = childWidth + margin.left;//确定下一个位置的坐标
}else{
left = margin.left;
top += context.getChildSize(i).height + margin.top + margin.bottom;
//绘制子组件(有优化)
context.paintChild(i,
transform: Matrix4.translationValues(left, top, 0.0) //位移
);
left += context.getChildSize(i).width + margin.left + margin.right;
}
}
}
getSize(BoxConstraints constraints) {
//指定Flow组件的大小
return Size(double.infinity, double.infinity);
}
@override
bool shouldRepaint(FlowDelegate oldDelegate) {
return oldDelegate != this;
}
}
body:Flow(
delegate: NightFlowDelegate(margin: EdgeInsets.all(1)),
children: <Widget>[
Container(color: Colors.yellow,width: 100,height: 100),
Container(color: Colors.blue,width: 100,height: 100),
Container(color: Colors.orange,width: 100,height: 100),
Container(color: Colors.red,width: 100,height: 100),
Container(color: Colors.deepPurpleAccent,width: 100,height: 100),
Container(color: Colors.indigoAccent,width: 100,height: 100),
Container(color: Colors.lightGreenAccent,width: 100,height: 100),
Container(color: Colors.greenAccent,width: 100,height: 100),
Container(color: Colors.yellow,width: 100,height: 100),
],
),