1. 项目的目录结构
文件夹 | 描述 |
---|---|
android | android平台相关代码 |
ios | ios平台相关代码 |
lib | Flutter相关代码,主要编写的文件在这个目录下 |
test | 存放测试代码 |
pubspec.yaml | 配置文件,存放第三方库的依赖项 |
入口文件、入口方法
- lib文件夹中的main.dart文件为入口文件
- main方法是Dart的入口方法,runApp方法是Flutter的入口方法
-
2. 自定义组件
materialApp
封装了应用程序实现Material Design所需要的一些widget,一般作为顶层widget使用
3. 基础组件
状态管理组件
在Flutter中自定义组件其实就是一个类,这个类继承StatelessWidget/StatefulWidget。
- vscode 快捷键插件Awesome Flutter Snippets
无状态组件
StatelessWidget 无状态组件,状态不可变的Widget有状态组件
StatefulWidget 有状态组件,持有的状态可能在widget生命周期改变Text 组件
组件重要参数说明
名称 | 功能 |
---|---|
textAlign | 文本对齐方式(center、left、right、justfy) |
textDirection | 文本方向(ltr从左至右、rtl从右至左) |
maxLines | 文本显示最大行数 |
overflow | 文本超出屏幕之后的处理方式(clip裁剪、fade渐隐、ellipsis省略号) |
textScaleFactor | 文本显示最大倍数 |
style | 字体的样式设置TextStyle |
TextStyle重要参数说明
名称 | 功能 |
---|---|
decoration | 文字装饰线 (none,lineThrough 删除线,overline 上划线,underline 下划线) |
decorationColor | 文字装饰线颜色 |
decorationStyle | 文字装饰线风格 (dashed,dotted 虚线,double 两根线,solid 一根线,wavy 波浪线) |
wordSpacing | 单词间隙 |
letterSpacing | 字母间隙 |
fontStyle | 字体样式 |
fontSize | 字体大小 |
color | 字体颜色 |
fontWeight | 字体粗细 |
Image 组件
Image.network 网络图片
名称 | 类型 | 说明 |
---|---|---|
alignment | Alignment | 图片的对齐方式 |
color | 设置图片背景颜色,通常和colorBlendMode一起使用 | |
colorBlendMode | BlendMode | 颜色混合 |
fit | BoxFit | 控制图片的拉伸和挤压 |
repeat | ImageRepeat | 图片平铺 |
Image.assets 本地图片
如何实现圆角以及实现圆形图片
- 通过Container 中的 decoration -> borderRadius
- clipOver
CircleAvatar (头像裁剪用的多)
// 通过Container 中的 decoration -> borderRadius
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(150),
image: DecorationImage(
image: NetworkImage(
'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3593964987,1999043304&fm=15&gp=0.jpg',
),
fit: BoxFit.cover,
),
// borderRadius: BorderRadius.all(Radius.circular(150))
)
// clipOver
child: ClipOval(
child: Image.asset(
'images/4.png',
width: 150,
height: 100,
),
)
//
CircleAvatar(
backgroundImage: NetworkImage(
"https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=1129084263,3532636474&fm=26&gp=0.jpg"),
)
AspectRatio 组件
AspectRatio根据设置调整子元素child的宽高比。
- AspectRatio首先会在布局限制条件允许的范围内尽可能的扩展,widget的高度是由宽度和比率决定的,类似于BoxFit中的contain,按照固定比率去尽量占满区域。
- 如果在满足所有限制条件过后无法找到一个可行的尺寸,AspectRatio最终将会去优先适应布局限制条件,而忽略所设置的比率
Card 卡片组件
| 参数 | 说明 | | —- | —- | | margin | 外边距 | | shadowColor | 阴影颜色 | | shape | 阴影效果,默认阴影效果为圆角的长方形边 | | color | 背景颜色 | | child | 子组件 |
按钮组件
- ElevatedButton
- TextButton
- OutlinedButton 线框按钮
- IconButton 图标按钮
- ButtonBar 按钮组
FloatingActionButton 浮动按钮
// 普通按钮
ElevatedButton(
onPressed: () {},
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.red),
elevation: MaterialStateProperty.all(20.0),
),
child: Text('阴影按钮'),
),
// 文字按钮
TextButton.styleFrom(
shape: RoundedRectangleBorder(
side: BorderSide(
color: Colors.yellow,
),
),
),
// 线框按钮
OutlinedButton(
onPressed: () {},
child: Container(
height: 50,
child: Text('outline'),
),
)
// 图标按钮
IconButton(
icon: Icon(Icons.ac_unit_outlined),
onPressed: () {},
)
// 按钮组
ButtonBar(
children: [
ElevatedButton(onPressed: () {}, child: Text('按钮组1')),
ElevatedButton(onPressed: () {}, child: Text('按钮组2')),
ElevatedButton(onPressed: () {}, child: Text('按钮组3'))
],
)
// 浮动按钮
floatingActionButton: FloatingActionButton(
onPressed: () {
this.setState(() {
this.currentIndex = 1;
});
},
backgroundColor: this.currentIndex == 2 ? Colors.blue : Colors.red,
child: Container(
width: 100.0,
height: 100.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(70),
// color: Colors.blue,
),
child: Icon(
Icons.add,
),
padding: EdgeInsets.all(8),
// margin: EdgeInsets.only(top: 10.0),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
表单组件
TextField 文本框组件
- Checkbox、CheckboxListTile 多选框组件
- Radio、RadioListTile
- 日期组件
- 自带组件
- 第三方组件
-
弹框组件
showDialog
AlertDialog
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('删除'),
content: Text('确认取消吗'),
actions: [
ElevatedButton(
onPressed: () {
Navigator.pop(context, 'cancel');
},
child: Text('取消'),
),
ElevatedButton(
onPressed: () {
Navigator.pop(context, 'ok');
},
child: Text('确定'),
)
],
);
},
);
SimpleDialog
showDialog(
context: context,
builder: (context) {
return SimpleDialog(
title: Text('选择内容'),
children: [
SimpleDialogOption(
child: Text('1'),
),
SimpleDialogOption(
child: Text('2'),
),
SimpleDialogOption(
child: Text('3'),
),
SimpleDialogOption(
child: Text('4'),
)
],
);
});
showModalBottomSheet
showModalBottomSheet(
context: context,
builder: (context) {
return Container(
height: 200.0,
child: Column(
children: [
ListTile(
title: Text('分享一'),
),
Divider(color: Colors.black),
ListTile(
title: Text('分享二'),
),
Divider(color: Colors.black),
ListTile(
title: Text('分享三'),
)
],
),
);
},
);
Fluttertoast.showToast
import 'package:fluttertoast/fluttertoast.dart';
Fluttertoast.showToast(
msg: '提示信息',
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.BOTTOM,
timeInSecForIos: 1,
backgroundColor: Colors.red,
);
自定义Dialog
sMaterial Design布局结构的基本实现,此类提供了用于显示drawer、snackbar和底部sheet的API
import 'package:flutter/material.dart';
BottomNavigationBar 底部导航组件
| 参数 | 说明 | | —- | —- | | currentIndex | 默认选中第几个 | | onTap | 点击回调方法 | | iconSize | icon大小 | | fixedColor | 选中的颜色 | | type | BottomNavigationBarType.fixed 可以有多个按钮 BottomNavigationBarType.shifting | | items | LIst BottomNavigationBarItem
底部导航条按钮集合 |
AppBar 顶部导航组件
参数 | 说明 |
---|---|
centerTitle | 无论安卓、ios都居中显示 |
leading | 头部导航前面展示的组件 |
actions | 头部导航后面展示的组件 |
bottom | 自定义组件 |
TabBar 组件
参数 | 说明 |
---|---|
tabs | 显示的标签内容,便是Tab对象,也可以是其他的widget |
controller | TabController对象 (结合SingleTickerProviderStateMixin) |
isScrollable | 是否可以滚动 |
indicatorColor | 指示器的颜色 |
indicatorWeight | 指示器高度 |
indicatorPadding | 底部指示器的高度 |
indicator | 指示器decoration,例如边框等 |
indicatorSize | 指示器大小计算方式 TabBarIndicatorSize.label 跟文字等宽 TabBarIndicatorSize.tab 跟tab等宽 |
labelColor | 选中的label的颜色 |
labelStyle | 选中的label的style |
labelPadding | 每个label的padding值 |
unselectedLabelColor | 未选中的label的颜色 |
unselectedLabelStyle | 未选中的label的style |
Container 组件
组件重要参数说明
名称 | 功能 |
---|---|
alignment | topCenter 顶部居中对齐 topLeft 顶部左对齐 topRight 顶部右对齐 center 水平垂直居中对齐 centerLeft 垂直居中水平居左对齐 centerRight 垂直居中水平居右对齐 bottomLeft 底部左对齐 bottomRight 底部右对齐 |
transform | 矩阵变换 |
decoration | 设置背景颜色、边框颜色 |
Padding
名称 | 说明 |
---|---|
padding | padding EdgeInsets设置填充的值 |
child | 自组件 |
5. 可滚动组件
ListView
水平列表、垂直列表
- 列表参数
| 名称 | 类型 | 说明 |
| —- | —- | —- |
| scrollDirection | Axis | Axis.horizontal 水平列表
Axis.vertical 垂直列表 | | padding | EdgeInsetsGeometry | 内边距 | | resolve | bool | 组件反向排序 | | children | List[Widget] | 列表元素 |
ListView(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.all(10),
children: <Widget>[
ListTile(
title: Text("标题"),
subtitle: Text("二级标题"),
leading: Icon(Icons.home),
// tileColor: Colors.red,
selectedTileColor: Colors.yellow),
ListTile(
title: Text("标题"),
subtitle: Text("二级标题"),
leading: Image.network(
'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3593964987,1999043304&fm=15&gp=0.jpg'),
trailing: Icon(Icons.offline_bolt, color: Colors.red, size: 28.0),
)
]
)
-
动态列表
map、for 等方法
-
GridView
网格列表
GridView.count | 名称 | 类型 | 说明 | | —- | —- | —- | | children | List[Widget] | 列表元素 | | crossAxisCount | Int | 一行的Widget数量 | | mainAxisSpacing | Double | 垂直Widget之间的间距 | | crossAxisSpacing | Double | 水平Widget之间的间距 | | childAspectRatio | Double | Widget的宽高比 |
GridView.builder | 名称 | 类型 | 说明 | | —- | —- | —- | | itemCount | Int | 列表数量 | | gridDelegate | SliverGridDelegateWithFixedCrossAxisCount | 列表样式之类的写在其中 | | itemBuilder | Widget | Widget元素 |
6. 布局类组件
线性布局
Row 水平布局组件
名称 | 说明 |
---|---|
mainAxisAlignment | 主轴的排序方式 |
crossAxisAlignment | 次轴的排序方式 stretch(次轴高度填满)、center、start、end |
children | 组件子元素 |
Column 垂直布局组件
名称 | 说明 |
---|---|
mainAxisAlignment | 主轴的排序方式 |
crossAxisAlignment | 次轴的排序方式 stretch(次轴高度填满)、center、start、end |
children | 组件子元素 |
弹性布局
Expanded
web端的flex布局
名称 | 说明 |
---|---|
flex | |
child | 子组件 |
对齐与相对定位 Stack 、Align
// Stack 和 Align
Stack(
children: [
Align(
alignment: Alignment.topCenter,
child: Icon(
Icons.ac_unit,
color: Colors.white,
),
),
Align(
alignment: Alignment.center,
child: Icon(
Icons.sanitizer,
color: Colors.white,
),
),
Align(
alignment: Alignment.bottomCenter,
child: Icon(
Icons.east,
color: Colors.white,
),
),
],
)
层叠布局 Stack 、Positioned
- 与Web中的绝对定位概念类似
stack参数说明
名称 | 说明 |
---|---|
alignment | 配置所有子元素的显示位置 |
children | 自组件 |
// Stack 和 Positioned
Stack(
children: [
Positioned(
left: 0,
top: 0,
child: Icon(
Icons.ac_unit,
color: Colors.white,
),
),
Positioned(
top: 0,
right: 0,
child: Icon(
Icons.sanitizer,
color: Colors.white,
),
),
]
)
流式布局 Wrap、Flow
Wrap
warp实现流式布局,单行的Wrap和Row表现基本一致,单列的Wrap则跟Column表现一致。但Row和Column都是单行单列的,Wrap则突破了这个限制,mainAxis上空间不足时,则向crossAxis上扩展显示。
属性 | 说明 |
---|---|
direction | 主轴方向,默认水平 |
alignment | 主轴的对齐方式 |
runAlignment | 纵轴的对齐方式 |
spacing | 主轴方向上的间距 |
runSpacing | 纵轴方向上的间距 |
children | 子组件 |
7. 路由
基本路由以及参数传递
// 基本路由
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return Search();
},
),
),
命名路由以及参数传递
// 命名路由
Navigator.pushNamed(context, '/search')
// 不传惨
routes: {
'/search': (context) => Search(),
'/list': (context) => List(),
},
// 传参数
onGenerateRoute: (RouteSettings settings) {
final name = settings.name;
final Function pageContentBuilder = this.routes[name];
Route route;
if (pageContentBuilder != null) {
if (settings.arguments != null) {
route = MaterialPageRoute(
builder: (context) {
return pageContentBuilder(context, arguments: settings.arguments);
},
);
}
} else {
route = MaterialPageRoute(
builder: (context) {
return pageContentBuilder(context);
},
);
}
return route;
},
);
路由替换
Navigator.pushReplacementNamed(
context,
'/search',
arguments: {
"title": "参数传递",
},
)
返回根路由
Navigator.of(context).pushAndRemoveUntil(
new MaterialPageRoute(
builder: (context) => Tabs(currentIndex: 1),
),
(route) => route == null)
8. 接口请求
- json字符串和Map类型的转换
- import ‘dart:convert’;
- json.encode
- json.decode
请求数据 http
import 'package:http/http.dart' as http;
var httpUrl = '';
var data = await http.get(httpUrl);
var data = await http.post(
httpUrl,
// headers: {'Content-Type': 'application/json; charset=utf-8'},
body: json.encode({'Phone': '18116462666', 'Password': '123456789'}),
);
请求数据 dio
import 'package:dio/dio.dart';
var httpUrl = '';
var dio = Dio();
Response result = await dio.get(httpUrl);
Response result = await dio.post(httpUrl, data: data);