组件目录
- 基础组件
- Text 文本
- Button 按钮a
- Image 图片
- TextField 输入框,TextFormField 表单
- Switch-开关,CheckBox-复选框,ProgressIndicator-进度条
- 布局组件
- Column 和 Row 竖向或者横向的线性布局
- Flex 弹性布局,按比例布局
- Wrap 流式布局
- Stack Positioned 绝对布局
- Align和Center 对齐与相对定位
- 容器组件
- Padding 留边距
- Container 容器-内外边距,宽高
- 装饰器Decoration 容器样式修改 BoxDecoration,ShapeDecoration,UnderlineTabIndicator等
- 约束Constraints 容器大小限制 ConstrainedBox,SizedBox,AspectRatio等
- 裁切类容器:ClipOval,ClipRRect,ClipRect
- Scaffold 页面骨架
- 可滚动组件
- ListView,GridView
- SingleScrollView
- CustomerScrollView
基础组件
- Text 文本
- Button 按钮
- Image 图片
- TextField 输入框,TextFormField 表单
- Switch-开关,CheckBox-复选框,ProgressIndicator-进度条
Text
Text(
"flutter text",
overflow: TextOverflow.clip,
textAlign: TextAlign.center, //textAlign 优先
textDirection: TextDirection.rtl, //textAlign 优先
style: TextStyle(),
),
Text.rich
Text.rich(
TextSpan(children: [
TextSpan(
text: "蓝色字体的文本",
style: TextStyle(color: Colors.blue),
),
TextSpan(
text: "红色字体的文本",
style: TextStyle(color: Colors.red),
),
TextSpan(
text: "大号的黄色字体文本",
style: TextStyle(color: Colors.yellow, fontSize: 30),
),
]),
style: TextStyle(fontSize: 4),
textAlign: TextAlign.left,
)
Button
- FlatButton--扁平的Button
- RaisedButton--凸起的,有阴影,点击有浮动效果
- OutlineButton--有边框的按钮
-
IconButton--图标按钮,不能加文字
自定义Button
常用属性有:
highlightColor: Colors.green,//按钮按下的背景颜色
splashColor: Colors.blue,//水波纹颜色
color: Colors.red,//背景颜色
disabledColor: Colors.black12,////按钮禁用的颜色
shape:ShapeBorder//形状
ShapeBorder主要有以下子类:
- RoundedRectangleBorder 圆角形
- BeveledRectangleBorder 尖括号形状
- CircleBorder 直接圆形
- ContinuousRectangleBorder 矩形
- StadiumBorder 操场400米跑道形状
- UnderlineInputBorder 下划线
Image
文件图片,网络图片,资源图片,内存中的图片
两种写法:
Image(
image: NetworkImage(image_0),
width: 100,
),
Image.network(image_0, width: 100, height: 100),
属性:
this.width, //图片的宽
this.height, //图片高度
this.color, //图片的混合色值
this.colorBlendMode, //混合模式
this.fit,//缩放模式
this.alignment = Alignment.center, //对齐方式
this.repeat = ImageRepeat.noRepeat, //重复方式
缩放模式 fit,直接看图对比
<article id="content" class="article-content" tabindex="0" style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); outline-style: none;">
TextField 和 TextFormField 输入框和表单提交校验
TextField(
//控制器,可以获取文本内容,清空文本框等操作_textEditingController=TextEditingController()
controller: _textEditingController,
//文本样式
style: TextStyle(
fontSize: 40,
color: Colors.red,
),
maxLines:10,//最大行数
minLines: 1,//最小行数--当字数超过一行的时候会自动增加高度变成两行
onChanged: (value) => {
//文字变化回调
setState(() {
textFieldStr = value;
})
},
),
TextField的属性很多,常用的看注释
TextFormField(
//当点击空白处的时候可以使用_focusNodePhone.unfocus()失去焦点进行影藏键盘
focusNode: _focusNodePhone,
autofocus: true,
//控制器
controller: _phoneController,
//输入框装饰器
decoration: InputDecoration(
labelText: "手机号",
hintText: "请输入手机号",
prefixIcon: Icon(
Icons.phone_android,
),
),
//表单提交,规则校验
validator: (value) {
if (value.startsWith("1") && value.length == 11) {
return null;
} else {
return "手机号不对";
}
},
),
开关:Switch
Switch(
value: isOpen,
onChanged: (value) {
setState(() {
isOpen = value;
});
},
复选框:Checkbox
Checkbox(
value: isOpen,
onChanged: (value) {
setState(() {
isOpen = value;
});
},
进度条 ProgressIndicator
CircularProgressIndicator -- 圆形
LinearProgressIndicator -- 线性
RefreshProgressIndicator -- 类似于下拉刷新的圆形进度条
布局类组件
- Column 和 Row 竖向或者横向的线性布局
- Flex 弹性布局,按比例布局
- Wrap 流式布局
- Stack Positioned 绝对布局
- Align和Center 对齐与相对定位
Column 和 Row 竖向或者横向的线性布局
以Column为例讲解,3个属性比较重要:
- mainAxisAlignment 主轴方向的对齐方式
- crossAxisAlignment 纵轴方向的对齐方式
- children 孩子Widget
mainAxisAlignment有6个
- start
- end
- center
- spaceBetween
- spaceAround
- spaceEvenly
具体效果看下图
Column(
mainAxisAlignment: MainAxisAlignment.start,//主轴方向的对齐方式
crossAxisAlignment: CrossAxisAlignment.start,//纵轴方向的对齐方式
children: <Widget>[
Text("start"),
Text("start"),
Text("start"),
Text("start"),
Text("start"),
],
),
crossAxisAlignment属性常用的有3个
- start
- center
- end
Flex 弹性布局,按比例布局
- Column和Row是继承Flex,用Flex也能实现两者的效果
- 用Flex实现按比例布局,需要结合Expanded进行指定比例
Flex(
direction: Axis.horizontal,//如果是垂直的话,需要指定父容器的高度,否则会报错
children: <Widget>[
Expanded(
flex: 1,//占
child: Container(color: Colors.orange, child: Text("flex=1")),
),
Expanded(
flex: 2,
child: Container(color: Colors.red, child: Text("flex=2")),
),
],
),
Wrap 流式布局
使用方式和Row和Colunm类似,会自动换行
Container(
color: Colors.blue,
height: 400,
child: Wrap(
//水平方向
direction: Axis.horizontal,
//主轴上child的间距
spacing: 10,
//纵轴child的间距
runSpacing: 50,
//主轴child的对齐方式
alignment: WrapAlignment.start,
//纵轴child的对齐方式
runAlignment: WrapAlignment.spaceEvenly,
//纵轴居中对齐
crossAxisAlignment: WrapCrossAlignment.center,
children: <Widget>[
Container(color: Colors.red, child: Text("AAAAAAAAAAAAAA")),
Container(
color: Colors.red,
child: OutlineButton(
child: Text("CCCCCCCCCCCCCCC"),
onPressed: () => {},
),
),
Container(color: Colors.red, child: Text("SSSSSSSSS")),
Container(color: Colors.red, child: Text("AAAAAA")),
Container(
color: Colors.red,
child: OutlineButton(
child: Text("按钮1111"),
onPressed: () => {},
),
),
],
),
),
Stack Positioned 绝对布局
Stack:绝对布局,使用Positioned进行定位,子widget相对于父widget进行定位
Container(
height: 100,
color: Colors.red,
child: ConstrainedBox(
constraints: BoxConstraints.expand(), //撑满父容器
child: Stack(
alignment: Alignment.center,
children: <Widget>[
Positioned(left: 0, top: 0, child: Text("左上角")),
Positioned(right: 0, top: 0, child: Text("右上角")),
Positioned(left: 0, bottom: 0, child: Text("左下角")),
Positioned(right: 0, bottom: 0, child: Text("右下角")),
//这里水平使用外层设置的居中对齐方式
Positioned(top: 0, child: Text("AA")),
//这里垂直和水平都是外层设置的居中对齐方式
Positioned(child: Text("BB")),
Positioned(bottom: 0, child: Text("CC")),
],
),
),
),
Align和Center,对齐与相对定位
单一孩子Widget,设置子组件的位置,并且根据子组件的大小设置自己的大小,Center是Align的一个包装类,不能设置对齐方式,对齐方式是居中对齐
Column(
children: <Widget>[
Container(
color: Colors.red,
child: Align(
//子Widget
child: Container(
color: Colors.blue,
child: Text("AAAAA"),
),
/*父Widget的宽度是子Widget的3倍*/
widthFactor: 3,
/*父Widget的高度是子Widget的2倍*/
heightFactor: 2,
alignment: Alignment.center,//或者 FractionalOffset(0.5, 0.5),
),
),
Container(
margin: EdgeInsets.only(top: 20),
color: Colors.red,
child: Center(
//子Widget
child: Container(
color: Colors.blue,
child: Text("AAAAA"),
),
/*父Widget的宽度是子Widget的3倍*/
widthFactor: 3,
/*父Widget的高度是子Widget的2倍*/
heightFactor: 2,
),
),
],
),
容器类组件
- Padding 留边距
- Container 容器-内外边距,宽高
- 装饰器Decoration 容器样式修改 BoxDecoration,ShapeDecoration,UnderlineTabIndicator等
- 约束Constraints 容器大小限制 ConstrainedBox,SizedBox,AspectRatio等
- 裁切类容器:ClipOval,ClipRRect,ClipRect
- Scaffold 页面骨架
Padding 内边距
Padding(
child: Text("AAAAAAAA"),
padding: EdgeInsets.fromLTRB(10,100, 30, 80),//依次为左,上,右,下设置边距
),
还可以使用以下方式快速添加边距,适应不同场景的需求
padding: EdgeInsets.all(10),//4个边都留10边距
padding: EdgeInsets.only(left: 10,bottom: 20),//可选参数,指定哪条边留边距
padding: EdgeInsets.symmetric(vertical: 10,horizontal: 20),//可选参数,上下边距10,左右边距20
Container 容器-内外边距,宽高
Container(
width: 300,//容器宽
height: 200,//容器高
padding: EdgeInsets.all(20),//内边距
margin: EdgeInsets.all(20),//外边距
// color: Colors.red,//背景色,和decoration属性互斥,只能设置一个,否则会报错
//装饰器
// decoration: ShapeDecoration(color: Colors.red, shape: CircleBorder()),
decoration: BoxDecoration(
color: Colors.blue,//背景颜色
borderRadius: BorderRadius.circular(20), //圆角
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.black26, //阴影的颜色
blurRadius: 10, //虚化的宽度
spreadRadius: 10, //阴影和原物大小的差值--不包括虚化的部分
offset: Offset(40, 40), //阴影的偏移量
),
],
),
//容器约束-大小限制
constraints: BoxConstraints(
minHeight: 100,
minWidth: 100,
maxWidth: 200,//这里限制了200,所以上面设置的宽度300无效
maxHeight: 150,
),
child: Text("AAAAAAAA"),
),
装饰器Decoration
上面Conatiner中用到了一个BoxDecoration,用于装饰Container容器的样式,圆角,背景色,阴影等,其实Container内部使用的是DecoratedBox,只是进行了一次封装,方便使用。Flutter除了提供BoxDecoration,还有ShapeDecoration,UnderlineTabIndicator,FlutterLogoDecoration,他们都是Decoration的子类。
约束Constraints
约束容器的大小,上面代码中的Container限制了最大最小的宽高,内部实现也是进行了一次封装,使用的是ConstrainedBox,另外Flutter还提供了SliverConstraints,在滚动布局中进行约束
如果不使用Container,直接使用DecoratedBox和ConstrainedBox也是可以的,自己去实现child,如下使用:
DecoratedBox(
decoration: BoxDecoration(
//背景颜色
color: Colors.blue, //圆角
borderRadius: BorderRadius.circular(20),
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.black26, //阴影的颜色
blurRadius: 10, //虚化的宽度
spreadRadius: 10, //阴影和原物大小的差值--不包括虚化的部分
offset: Offset(40, 40), //阴影的偏移量
),
],
),
child: Text("AAAAAAAA"),
),
ConstrainedBox(
constraints: BoxConstraints(
minHeight: 100,
minWidth: 100,
maxWidth: 200, //这里限制了200,所以上面设置的宽度300无效
maxHeight: 150,
),
child: Container(
color: Colors.red,
width: 100,
child: Center(child: Text("AAAAAAA")),
),
),
尺寸限制容器:ConstrainedBox,SizedBox,AspectRatio等
ConstrainedBox:大小约束
SizedBox:指定大小的容器
UnconstrainedBox:解除父容器大小限制
AspectRatio:指定比例
他们都是SingleChildRenderObjectWidget的子类,都只有一个child widget。
Container(
margin: EdgeInsets.only(top: 10),
child: SizedBox(
width: 100,
height: 100,
child: Container(
color: Colors.red,
width: 50,//这里设置无效
height: 200,//这里设置无效
child: Center(child: Text("AAAAAAA")),
),
),
),
Container(
margin: EdgeInsets.only(top: 20),
width: 100, //指定宽为100
child: AspectRatio(
aspectRatio: 0.5, //父容器宽为100,宽高比为0.5,则高度为200
child: Container(
color: Colors.red,
child: Text(
"11111111111111111111111111111111111111111111111111111111111111111111111111111"
"11111111111111111111111111111111111111111111111111111111111111111111111111"
"11111111111111111111111111111111111111111111111111111111111111111111111111"),
),
),
),
裁切类容器:ClipOval,ClipRRect,ClipRect
圆形头像,圆角矩形,矩形裁切
ClipOval(
child: Image.network(
IMAGE_0,
fit: BoxFit.cover,
width: 50,
height: 50,
),
),
ClipRect(
child: Container(
color: Colors.black12,
child: Image.network(
IMAGE_0,
fit: BoxFit.cover,
width: 100,
height: 100,
),
),
),
Container(
margin: EdgeInsets.only(top: 10),
child: ClipRRect(
borderRadius: BorderRadius.all(
Radius.circular(30),
),
child: Container(
color: Colors.black12,
child: Image.network(
IMAGE_0,
fit: BoxFit.cover,
width: 200,
height: 200,
),
),
),
)
Scaffold 骨架容器
- 完整的骨架容器包含了
- 顶部导航栏:appBar
- 内容体:body
- 左侧和右侧的抽屉:drawer、endDrawer
- 底部菜单导航:bottomNavigationBar
- 悬浮按钮:floatingActionButton
Scaffold(
//顶部导航
appBar: AppBar(
leading: Builder(
builder: (BuildContext context) {
return IconButton(
icon: const Icon(Icons.menu),
onPressed: () => {
//点击左上角的按钮
Scaffold.of(context).openDrawer()
},
);
},
),
title: Text("Scaffold的使用"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.folder_shared),
onPressed: () => {},
),
IconButton(
icon: Icon(Icons.share),
onPressed: () => {},
),
],
bottom: TabBar(
controller: _tabController,
tabs: tabs.map((e) => Tab(text: e)).toList(),
),
),
//内容体
body: TabBarView(
controller: _tabController,
children: <Widget>[
Center(child: Text(tabs[0])),
Center(child: Text(tabs[1])),
Center(child: Text(tabs[2])),
],
),
//左边抽屉
drawer: Container(
width: 250,
color: Colors.white,
child: Center(
child: FlatButton(
child: Text("左侧抽屉"),
onPressed: () => {},
),
),
),
//右边抽屉
endDrawer: Drawer(
child: MediaQuery.removePadding(
context: context, // removeTop: true,//移除抽屉菜单顶部默认留白
child: ListView(
children: <Widget>[
ListTile(leading: const Icon(Icons.add), title: const Text('Add account0')),
ListTile(leading: const Icon(Icons.add), title: const Text('Add account1')),
ListTile(leading: const Icon(Icons.add), title: const Text('Add account2')),
ListTile(leading: const Icon(Icons.add), title: const Text('Add account3')),
],
),
),
),
//底部菜单导航
bottomNavigationBar: BottomNavigationBar(
currentIndex: index,
onTap: (i) => {
setState(() {
index = i;
})
},
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(icon: Icon(Icons.map), title: Text(tabs[0])),
BottomNavigationBarItem(icon: Icon(Icons.map), title: Text(tabs[1])),
BottomNavigationBarItem(icon: Icon(Icons.map), title: Text(tabs[2])),
],
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () => {},
),
);
<article id="content" class="article-content" tabindex="0" style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); outline-style: none;">
滚动组件
- ListView,GridView
- SingleScrollView
- CustomerScrollView
滚动组件分为两类:
- 具有延迟加载特性的滚动组件,如:ListView,GridView
- 一次性加载所有组件,如SingleChildScrollView
如果说页面上的内容很多,大大的超过了一个屏幕,使用SingleChildScrollView,会比较耗内存,性能也会比较差
建议使用ListView或者GridView这种具有延迟加载特性的组件
下面使用ListView示例,属性说明见代码注释
Container(
child: Flex(
direction: Axis.horizontal,
children: <Widget>[
Expanded(
flex: 1,
child: Container(
color: Colors.white,
child: ListView.builder(
itemExtent: 100, //指定子组件的高度,如果指定了效率更高,不用每次都去计算子组件的高度了
itemCount: 100, //子组件的个数
shrinkWrap: false, //ListView的高度是否是内容包裹,否则撑到最大,如果ListView的父容器没有边界,则必须设置为true
itemBuilder: (BuildContext context, int index) {
return Container(
height: 200, //上面指定了itemExtent之后,该属性无效
margin: EdgeInsets.all(10), color: Colors.red,
);
},
),
),
),
Expanded(
flex: 1,
child: Container(
color: Colors.yellow,
//带分割线的ListView构造函数
child: ListView.separated(
itemCount: 10, //子组件的个数
shrinkWrap: false, //ListView的高度是否是内容包裹,否则撑到最大,如果ListView的父容器没有边界,则必须设置为true
itemBuilder: (BuildContext context, int index) {
return Container(
height: 100, //上面指定了itemExtent之后,该属性无效
// margin: EdgeInsets.fromLTRB(10, 5, 10, 5),
color: Colors.blue,
);
},
separatorBuilder: (BuildContext context, int index) {
return Divider(
color: Colors.black,
height: 30,
//间距的高度-包括了线的高度
thickness: 0.1,
//线条的高度
indent: 10,
//左边距
endIndent: 10, //右边距
);
},
),
),
),
],
)),
使用SingleScrollView
SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
height: 100,
color: Colors.red,
child: Center(
child: Text("SingleChildScrollView的使用"),
),
),
Container(
height: 400,
color: Colors.blue,
child: Center(
child: Text("SingleChildScrollView的使用"),
),
),
Container(
height: 400,
color: Colors.yellow,
child: Center(
child: Text("SingleChildScrollView的使用"),
),
),
],
),