前言
紧接上文界面篇,上文中在构建布局的时候因为是直接将文字图片显示出来的,所以消息类Message
,和日知录类One
都是采用的无状态的StatelessWidget
类,这次我们需要调用接口,然后将返回的数据动态的显示到那两个控件上去,StatelessWidget
类已经无法满足需求了,这个时候我们需要使用Flutter提供的另一个类StatefulWidget
,一旦控件继承了这个类则说明该空间是一个有状态的控件,可以进行动态更新等。
- 推荐阅读: 《StatefulWidget》, 《State.setState》,《为您的Flutter应用程序添加交互》
到目前为止,我们只使用了无状态的widget。无状态widget从它们的父widget接收参数, 它们被存储在
final
型的成员变量中。 当一个widget被要求构建时,它使用这些存储的值作为参数来构建widget。
为了构建更复杂的体验 - 例如,以更有趣的方式对用户输入做出反应 - 应用程序通常会携带一些状态。 Flutter使用StatefulWidget
来满足这种需求。StatefulWidget
是特殊的widget,它知道如何生成State对象,然后用它来保持状态。
解析
那么该如何创建一个有状态的widget,同时又如何进行网络请求并对控件的状态进行更新呢?我们一个一个的解决。
- 创建一个有状态的
Message
控件
//消息
class Message extends StatefulWidget {
@override
MessageState createState() => new MessageState();
}
class MessageState extends State {
@override
Widget build(BuildContext context) {
//这里创建页面
}
}
build函数的内容其实和之前创建无状态的Message
控件的是一样的,直接复制来就好
@override
Widget build(BuildContext context) {
return new Padding(
padding: new EdgeInsets.all(18.0),
child: new Column(
children: [
new Container(
child: new Row(
children: [
new Icon(
Icons.message,
color: Colors.black26,
size: 17.0,
),
new Container(
margin: new EdgeInsets.only(left: 5.0),
child: new Text(
'消息',
style: new TextStyle(color: Color(0xFF888888)),
),
)
],
),
),
new Divider(
color: Color(0xFF888888),
),
new Container(
margin: new EdgeInsets.all(10.0),
child: new Text("这里是消息"),
),
new Divider(
color: Color(0xFF888888),
)
],
),
);
}
- 进行网络请求并更新控件
在flutter中进行网络请求有两种方式
- 在Flutter中发起HTTP网络请求
- 开源库——dio
在这里推荐使用第二种,dio是一个强大的Dart Http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载、超时等。和安卓里的OkHttp类似。具体用法可以查看传送门,文档写的很详细。
回到该应用,在这里我们需要创建一个getMessage()
方法,并通过get请求相应的接口,然后对返回的res进行解析即可,如下所示:
String message = "这里是消息模块";
@override
void initState() {
super.initState();
getMessage();
}
//获取消息
void getMessage() {
Dio().get(Constant.GET_MSG).then((res) {
if (res.statusCode == 200) {
int code = res.data['code'];
if (code == 200) {
String info = res.data['info'][0];
print(info);
setState(() {
message = info;
});
}
}
});
}
说明一下:
- 调用setState()是至关重要的,因为它告诉框架控件的状态已经改变,控件应该重新绘制。在这里的作用就是将之前设置的
message
变量变为从接口中获取的变量。 - json的解析,推荐阅读《在 Flutter 中解析复杂的 JSON》
- 我们如果需要在控件一开始渲染的时候就要发送网络请求,需要在
initState()
函数中调用getMessage()
方法
该页代码
因为日知录部分的基本上也是网络请求和动态渲染控件,道理是一致的,所以我就直接在这里贴上代码了。
import 'package:flutter/material.dart';
import 'package:flutter_guohe/common/eventBus.dart';
import 'package:dio/dio.dart';
import 'package:flutter_guohe/views/customview.dart';
import 'package:flutter_guohe/utils/constant.dart';
class Today extends StatefulWidget {
@override
TodayState createState() => new TodayState();
}
class TodayState extends State {
//打开drawer
void openDrawer() {
eventBus.fire(new EventOpenDrawer(true));
}
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
leading: new IconButton(
icon: Icon(Icons.home),
onPressed: () {
//打开drawer
openDrawer();
},
),
title: new Text("今日"), //设置标题内容
backgroundColor: Color.fromARGB(255, 119, 136, 213), //设置appbar背景颜色
centerTitle: true, //设置标题是否局中
),
body: new ListView(
children: [
new Header(), //头部
new BigDivider(),
new TodayKb(), //今日课表
new BigDivider(),
new Message(), //消息
new BigDivider(),
new One() //日知录
],
),
),
);
}
}
//首页的头部信息
class Header extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Container(
height: 100.0,
margin: new EdgeInsets.all(8.0),
child: new Row(
children: [
new Expanded(
child: new Column(
children: [
//头像
new Container(
width: 60.0,
height: 60.0,
margin: new EdgeInsets.all(8.0),
decoration: BoxDecoration(
image: DecorationImage(
image: new AssetImage('assets/imgs/ic_menu_score.png'),
//从Assets加载图片
fit: BoxFit.cover,
),
shape: BoxShape.circle,
),
),
new Text(
'查成绩',
textAlign: TextAlign.center,
)
],
),
flex: 1,
),
new Expanded(
child: new Column(
children: [
//头像
new Container(
width: 60.0,
height: 60.0,
margin: new EdgeInsets.all(8.0),
decoration: BoxDecoration(
image: DecorationImage(
image: new AssetImage('assets/imgs/ic_menu_pe.png'),
//从Assets加载图片
fit: BoxFit.cover,
),
shape: BoxShape.circle,
),
),
new Text(
'查体育',
textAlign: TextAlign.center,
)
],
),
flex: 1,
),
new Expanded(
child: new Column(
children: [
//头像
new Container(
width: 60.0,
height: 60.0,
margin: new EdgeInsets.all(8.0),
decoration: BoxDecoration(
image: DecorationImage(
image: new AssetImage('assets/imgs/ic_menu_bus.png'),
//从Assets加载图片
fit: BoxFit.cover,
),
shape: BoxShape.circle,
),
),
new Text(
'查校车',
textAlign: TextAlign.center,
)
],
),
flex: 1,
),
new Expanded(
child: new Column(
children: [
//头像
new Container(
width: 60.0,
height: 60.0,
margin: new EdgeInsets.all(8.0),
decoration: BoxDecoration(
image: DecorationImage(
image: new AssetImage('assets/imgs/ic_menu_system.png'),
//从Assets加载图片
fit: BoxFit.cover,
),
shape: BoxShape.circle,
),
),
new Text(
'校园系统',
textAlign: TextAlign.center,
)
],
),
flex: 1,
),
new Expanded(
child: new Column(
children: [
//头像
new Container(
width: 60.0,
height: 60.0,
margin: new EdgeInsets.all(8.0),
decoration: BoxDecoration(
image: DecorationImage(
image: new AssetImage('assets/imgs/ic_menu_more.png'),
//从Assets加载图片
fit: BoxFit.cover,
),
shape: BoxShape.circle,
),
),
new Text(
'更多',
textAlign: TextAlign.center,
)
],
),
flex: 1,
),
],
),
);
}
}
//今日课表
class TodayKb extends StatefulWidget {
@override
TodayKbState createState() => new TodayKbState();
}
class TodayKbState extends State {
@override
Widget build(BuildContext context) {
//跳转至课表
_toKb() {
print('跳转至课表');
}
return new Padding(
padding: new EdgeInsets.all(18.0),
child: new Column(
children: [
new Container(
child: new Row(
children: [
new Icon(
Icons.camera,
color: Colors.black26,
size: 17.0,
),
new Container(
margin: new EdgeInsets.only(left: 5.0),
child: new Text(
'今日课表',
style: new TextStyle(color: Color(0xFF888888)),
),
)
],
),
),
new Divider(
color: Color(0xFF888888),
),
new Container(
margin: new EdgeInsets.only(top: 30.0, bottom: 2.0),
child: new Text("今天居然没有课~" + "\uD83D\uDE01"),
),
new GestureDetector(
child: new Container(
margin: new EdgeInsets.only(top: 30.0, bottom: 2.0),
child: new Text('点我查看完整课表',
style: new TextStyle(
color: Color(
0xFF888888,
),
fontSize: 12.0)),
),
onTap: _toKb,
),
],
),
);
}
}
//消息
class Message extends StatefulWidget {
@override
MessageState createState() => new MessageState();
}
class MessageState extends State {
String message = "这里是消息模块";
@override
void initState() {
super.initState();
getMessage();
}
//获取消息
void getMessage() {
Dio().get(Constant.GET_MSG).then((res) {
if (res.statusCode == 200) {
int code = res.data['code'];
if (code == 200) {
String info = res.data['info'][0];
print(info);
setState(() {
message = info;
});
}
}
});
}
@override
Widget build(BuildContext context) {
return new Padding(
padding: new EdgeInsets.all(18.0),
child: new Column(
children: [
new Container(
child: new Row(
children: [
new Icon(
Icons.message,
color: Colors.black26,
size: 17.0,
),
new Container(
margin: new EdgeInsets.only(left: 5.0),
child: new Text(
'消息',
style: new TextStyle(color: Color(0xFF888888)),
),
)
],
),
),
new Divider(
color: Color(0xFF888888),
),
new Container(
margin: new EdgeInsets.all(10.0),
child: new Text(message),
),
new Divider(
color: Color(0xFF888888),
)
],
),
);
}
}
//日知录
class One extends StatefulWidget {
@override
OneState createState() => new OneState();
}
class OneState extends State {
String date = "2018/09/14";
String imgUrl = 'http://image.wufazhuce.com/Fn5E1UnrcvN0jwFRiOtDZ2WnQa4N';
String imgAuthor = "Fahmi Ramadhan";
String imgKind = "摄影";
String url = "http://m.wufazhuce.com/one/2202";
String word = "恋爱不是用谈的,是坠入的。";
String wordFrom = "《寂寞东京铁塔》";
//获取日知录的内容
void getOneContent() {
FormData formData = new FormData.from(
{"TransCode": "030111", "OpenId": "123456789", "Body": "123456789"});
Dio().post(Constant.ONE, data: formData).then((res) {
setState(() {
date = res.data['Body']['date']
.toString()
.split(" ")[0]
.replaceAll("-", "/");
imgUrl = res.data['Body']['img_url'];
imgAuthor = res.data['Body']['img_author'];
imgKind = res.data['Body']['img_kind'];
url = res.data['Body']['url'];
word = res.data['Body']['word'];
wordFrom = res.data['Body']['word_from'];
});
});
}
@override
void initState() {
// TODO: implement initState
super.initState();
getOneContent();
}
@override
Widget build(BuildContext context) {
return new Padding(
padding: new EdgeInsets.all(18.0),
child: new Column(
children: [
new Container(
child: new Row(
children: [
new Icon(
Icons.email,
color: Colors.black26,
size: 17.0,
),
new Container(
margin: new EdgeInsets.only(left: 5.0),
child: new Text(
'日知录',
style: new TextStyle(color: Color(0xFF888888)),
),
)
],
),
),
new Divider(
color: Color(0xFF888888),
),
new Container(
margin: new EdgeInsets.all(10.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
new Text(
date,
style: new TextStyle(color: Color(0xFF888888)),
),
new Margin(indent: 6.0),
new Image(image: new NetworkImage(imgUrl)),
new Margin(indent: 6.0),
new Text(
imgAuthor + " | " + imgKind,
style: new TextStyle(color: Color(0xFF888888)),
),
new Margin(indent: 6.0),
new Text(
word,
textAlign: TextAlign.center,
style: new TextStyle(color: Color(0xFF888888)),
),
new Margin(indent: 6.0),
new Text(
wordFrom,
style: new TextStyle(color: Color(0xFF888888)),
)
],
),
),
new Divider(
color: Color(0xFF888888),
)
],
),
);
}
}