前言
这一篇,我们说说开发中会用到的地方。
页面跳转
Flutter
的页面跳转,主要是通过Navigator
来实现,类似原生中的路由,分为静态和动态2种方式。
- 静态
首先要在MaterialApp
的routes
中进行注册
MaterialApp(
routes: {
'base': (BuildContext context) {
return BaseDemo();
},
'login': (BuildContext context) {
return LoginDemo();
}
},
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.brown,
),
home: MainDemo(),
);
然后进行跳转
RaisedButton(
child: Text('BaseWidget'),
onPressed: () {
Navigator.pushNamed(context, 'base');
},
)
这种方式的缺点也比较明显,首先需要注册,其次是不能传递参数
- 动态
需要构建MaterialPageRoute
RaisedButton(
child: Text('PageView'),
onPressed: () {
Navigator.push(context,
new MaterialPageRoute(builder: (BuildContext context) {
return PageViewDemo();
}));
},
)
- 关闭页面
主要是通过pop
方法来实现
Navigator.of(context).pop();
- 传递参数
首先,需要在目标Widget
中定义参数
class LoginDemo extends StatefulWidget {
@override
_LoginDemoState createState() => _LoginDemoState(tel);
final String tel;
LoginDemo({Key key, @required this.tel}) : super(key: key);
}
再传递参数
RaisedButton(
child: Text('Login'),
onPressed: () {
Navigator.push(context,
new MaterialPageRoute(builder: (BuildContext context) {
return LoginDemo(tel: '18700000000');
}));
},
)
目标Widget
取值,这里用到的是上一篇中的登录示例,详情可以查看【Flutter】开发之高级Widget(三)
class _LoginDemoState extends State<LoginDemo> {
String tel;
_LoginDemoState(this.tel);
TextEditingController user = new TextEditingController();
TextEditingController pwd = new TextEditingController();
@override
void initState() {
super.initState();
setState(() {
user.text = tel;
});
}
}
这里通过setState
触发Widget
重新构建刷新,将传递来的值设置给目标TextField
。
- 回传参数
首先是在关闭时,加入参数
Navigator.of(context).pop('0000000');
接收时,静态和动态方式的参数回传都是通过then
方法来完成的,这里就以动态方式为例
RaisedButton(
child: Text('Login'),
onPressed: () {
Navigator.push(context,
new MaterialPageRoute(builder: (BuildContext context) {
return LoginDemo(tel: '18700000000');
})).then((onValue) {
buildDialog(context, onValue);
});
},
)
void buildDialog(BuildContext context, String text) {
showDialog(
context: context,
builder: (BuildContext content) {
return AlertDialog(
title: Text("提示"),
content: Text(text),
actions: <Widget>[
GestureDetector(
child: Container(
child: Text('关闭'),
),
onTap: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
网络请求
flutter
内置HttpClient
可以用来做网络请求,但是官方建议使用 dio
官方原话:
HttpClient
本身功能较弱,很多常用功能都不支持。我们建议您使用dio 来发起网络请求,它是一个强大易用的dart http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载
我们就从善如流,直接使用dio
来实现网络请求
在pubspec.yaml
文件中添加依赖 dio: ^2.1.4
void getData() {
Dio dio = new Dio();
dio.request(
//使用自己的接口
'https://***/module/index.php?ctl=user&act=expertList',
data: {"p", "1"},
).then((onValue) {
print(onValue);
setState(() {
jsonString = onValue;
});
});
}
关于dio
的更多用法,请参考 dio 官方文档
将请求返回的数据展示到Text
上
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('NetDemo'),
actions: <Widget>[
RaisedButton(
child: Text('发起请求'),
onPressed: () {
getData();
},
),
],
),
body: Container(
child: Text('${jsonString}'),
),
);
}
JSON 序列化
上一步中,我们拿到了网络请求返回的json
,怎么把它转换为对象呢?这就涉及到了序列化
- 1.
flutter
内置的json
,老版本中为JSON
首先,添加导入
import 'dart:convert';
void getData() {
Dio dio = new Dio();
dio.request(
'https://***/module/index.php?ctl=user&act=expertList',
data: {"p", "1"},
).then((onValue) {
print(onValue);
//dynamic 代表动态数据类型 即可以是数字、字符串等任意类型
Map<String, dynamic> list = json.decode(onValue.toString());
setState(() {
data = list['data'];
});
});
}
使用数据
Widget _listView() {
return ListView.builder(
itemBuilder: (context, index) {
return MoveItem(data[index]);
},
itemCount: data.length,
);
}
class MoveItem extends StatelessWidget {
var model;
MoveItem(this.model);
@override
Widget build(BuildContext context) {
return Container(
child: Image.network(
'http://chuangfen.oss-cn-hangzhou.aliyuncs.com' +
model['head_image'],
),
);
}
虽然说问题解决了,但是这种方式的弊端很明显,我们直到运行时才知道值的类型,这样会失去了大部分静态类型语言特性:类型安全、自动补全和最重要的编译时异常。这样一来,我们的代码可能会变得非常容易出错。
- 2.手动序列化
只需要添加BaseModel
,并传入泛型,在其中添加json
转对象的方法即可。
添加BaseModel
import 'dart:convert';
class BaseModel<T> {
int status;
String msg;
T data;
BaseModel(this.status, this.msg, this.data);
BaseModel.fromJson(String jsonString) {
Map<String, dynamic> data = json.decode(jsonString);
BaseModel(data['status'], data['msg'], data['data']);
}
Map<String, dynamic> toJson() => {
'status': status,
'msg': msg,
'data': data,
};
}
添加ExpertModel
,
class ExpertModel {
String nick_name;
String head_image;
String id;
String signature;
}
这时,就可以这样使用
void getData() {
Dio dio = new Dio();
dio.request(
'https://www.yfbr2018.com/module/index.php?ctl=user&act=expertList',
data: {"p", "1"},
).then((onValue) {
BaseModel<List<ExpertModel>> baseModel =
BaseModel<List<ExpertModel>>.fromJson(onValue.toString());
setState(() {
jsonString = onValue;
data = baseModel.data;
});
});
}
class MoveItem extends StatelessWidget {
ExpertModel model;
MoveItem(this.model);
@override
Widget build(BuildContext context) {
return Container(
child: Image.network(
'http://chuangfen.oss-cn-hangzhou.aliyuncs.com' +
model.head_image,
),
);
}