前言
緊接上文界面篇,上文中在構(gòu)建布局的時(shí)候因?yàn)槭侵苯訉⑽淖謭D片顯示出來(lái)的,所以消息類Message,和日知錄類One都是采用的無(wú)狀態(tài)的StatelessWidget類,這次我們需要調(diào)用接口,然后將返回的數(shù)據(jù)動(dòng)態(tài)的顯示到那兩個(gè)控件上去,StatelessWidget類已經(jīng)無(wú)法滿足需求了,這個(gè)時(shí)候我們需要使用Flutter提供的另一個(gè)類StatefulWidget,一旦控件繼承了這個(gè)類則說(shuō)明該空間是一個(gè)有狀態(tài)的控件,可以進(jìn)行動(dòng)態(tài)更新等。
到目前為止,我們只使用了無(wú)狀態(tài)的widget。無(wú)狀態(tài)widget從它們的父widget接收參數(shù), 它們被存儲(chǔ)在
final型的成員變量中。 當(dāng)一個(gè)widget被要求構(gòu)建時(shí),它使用這些存儲(chǔ)的值作為參數(shù)來(lái)構(gòu)建widget。
為了構(gòu)建更復(fù)雜的體驗(yàn) - 例如,以更有趣的方式對(duì)用戶輸入做出反應(yīng) - 應(yīng)用程序通常會(huì)攜帶一些狀態(tài)。 Flutter使用StatefulWidget來(lái)滿足這種需求。StatefulWidget是特殊的widget,它知道如何生成State對(duì)象,然后用它來(lái)保持狀態(tài)。
解析
那么該如何創(chuàng)建一個(gè)有狀態(tài)的widget,同時(shí)又如何進(jìn)行網(wǎng)絡(luò)請(qǐng)求并對(duì)控件的狀態(tài)進(jìn)行更新呢?我們一個(gè)一個(gè)的解決。
- 創(chuàng)建一個(gè)有狀態(tài)的
Message控件
//消息
class Message extends StatefulWidget {
@override
MessageState createState() => new MessageState();
}
class MessageState extends State<Message> {
@override
Widget build(BuildContext context) {
//這里創(chuàng)建頁(yè)面
}
}
build函數(shù)的內(nèi)容其實(shí)和之前創(chuàng)建無(wú)狀態(tài)的Message控件的是一樣的,直接復(fù)制來(lái)就好
@override
Widget build(BuildContext context) {
return new Padding(
padding: new EdgeInsets.all(18.0),
child: new Column(
children: <Widget>[
new Container(
child: new Row(
children: <Widget>[
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),
)
],
),
);
}
- 進(jìn)行網(wǎng)絡(luò)請(qǐng)求并更新控件
在flutter中進(jìn)行網(wǎng)絡(luò)請(qǐng)求有兩種方式
- 在Flutter中發(fā)起HTTP網(wǎng)絡(luò)請(qǐng)求
-
開(kāi)源庫(kù)——dio
在這里推薦使用第二種,dio是一個(gè)強(qiáng)大的Dart Http請(qǐng)求庫(kù),支持Restful API、FormData、攔截器、請(qǐng)求取消、Cookie管理、文件上傳/下載、超時(shí)等。和安卓里的OkHttp類似。具體用法可以查看傳送門(mén),文檔寫(xiě)的很詳細(xì)。
回到該應(yīng)用,在這里我們需要?jiǎng)?chuàng)建一個(gè)getMessage()方法,并通過(guò)get請(qǐng)求相應(yīng)的接口,然后對(duì)返回的res進(jìn)行解析即可,如下所示:
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;
});
}
}
});
}
說(shuō)明一下:
- 調(diào)用setState()是至關(guān)重要的,因?yàn)樗嬖V框架控件的狀態(tài)已經(jīng)改變,控件應(yīng)該重新繪制。在這里的作用就是將之前設(shè)置的
message變量變?yōu)閺慕涌谥蝎@取的變量。 - json的解析,推薦閱讀《在 Flutter 中解析復(fù)雜的 JSON》
- 我們?nèi)绻枰诳丶婚_(kāi)始渲染的時(shí)候就要發(fā)送網(wǎng)絡(luò)請(qǐng)求,需要在
initState()函數(shù)中調(diào)用getMessage()方法
該頁(yè)代碼
因?yàn)槿罩洸糠值幕旧弦彩蔷W(wǎng)絡(luò)請(qǐng)求和動(dòng)態(tài)渲染控件,道理是一致的,所以我就直接在這里貼上代碼了。
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<Today> {
//打開(kāi)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: () {
//打開(kāi)drawer
openDrawer();
},
),
title: new Text("今日"), //設(shè)置標(biāo)題內(nèi)容
backgroundColor: Color.fromARGB(255, 119, 136, 213), //設(shè)置appbar背景顏色
centerTitle: true, //設(shè)置標(biāo)題是否局中
),
body: new ListView(
children: <Widget>[
new Header(), //頭部
new BigDivider(),
new TodayKb(), //今日課表
new BigDivider(),
new Message(), //消息
new BigDivider(),
new One() //日知錄
],
),
),
);
}
}
//首頁(yè)的頭部信息
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: <Widget>[
new Expanded(
child: new Column(
children: <Widget>[
//頭像
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(
'查成績(jī)',
textAlign: TextAlign.center,
)
],
),
flex: 1,
),
new Expanded(
child: new Column(
children: <Widget>[
//頭像
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: <Widget>[
//頭像
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: <Widget>[
//頭像
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(
'校園系統(tǒng)',
textAlign: TextAlign.center,
)
],
),
flex: 1,
),
new Expanded(
child: new Column(
children: <Widget>[
//頭像
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<TodayKb> {
@override
Widget build(BuildContext context) {
//跳轉(zhuǎn)至課表
_toKb() {
print('跳轉(zhuǎn)至課表');
}
return new Padding(
padding: new EdgeInsets.all(18.0),
child: new Column(
children: <Widget>[
new Container(
child: new Row(
children: <Widget>[
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("今天居然沒(méi)有課~" + "\uD83D\uDE01"),
),
new GestureDetector(
child: new Container(
margin: new EdgeInsets.only(top: 30.0, bottom: 2.0),
child: new Text('點(diǎn)我查看完整課表',
style: new TextStyle(
color: Color(
0xFF888888,
),
fontSize: 12.0)),
),
onTap: _toKb,
),
],
),
);
}
}
//消息
class Message extends StatefulWidget {
@override
MessageState createState() => new MessageState();
}
class MessageState extends State<Message> {
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: <Widget>[
new Container(
child: new Row(
children: <Widget>[
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<One> {
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 = "戀愛(ài)不是用談的,是墜入的。";
String wordFrom = "《寂寞東京鐵塔》";
//獲取日知錄的內(nèi)容
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: <Widget>[
new Container(
child: new Row(
children: <Widget>[
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: <Widget>[
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),
)
],
),
);
}
}