前言
這一篇,我們說說開發中會用到的地方。
頁面跳轉
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,
),
);
}
複製程式碼