實現(xiàn)效果:

需要使用到的第三方網(wǎng)絡(luò)庫:dio
在pubspec.yaml中添加第三方庫(相當于Android Studio中的build gradle目錄)
dio: ^0.0.14 (dio第三方庫名,^后面代表版本號,點擊packages get后完成依賴)
使用干貨提供的JSON數(shù)據(jù)。
http://gank.io/api/data/
json格式如下:
{
"error": false,
"results": [
{
"_id": "5b3d883f421aa906e5b3c6f1",
"createdAt": "2018-07-05T10:53:51.361Z",
"desc": "2018-07-05",
"publishedAt": "2018-07-05T00:00:00.0Z",
"source": "web",
"type": "\u798f\u5229",
"url": "http://ww1.sinaimg.cn/large/0065oQSqly1fsysqszneoj30hi0pvqb7.jpg",
"used": true,
"who": "lijinshanmx"
}
]
}
第一步:
建立JSON所對應(yīng)得model類,解析過程在FLModel.formJson()中處理,對應(yīng)key即可解析,這里注意類型必須對應(yīng),否則解析失敗,比如返回String類型,你聲明時卻是int,這里不會自動轉(zhuǎn)換,導(dǎo)致數(shù)據(jù)無法解析出來。
/解析類
class FLModle{
final String _id;
final String createdAt;
final String desc;
final String publishedAt;
final String source;
final String type;
final String url;
final bool used;
final String who;
const FLModle(this._id, this.createdAt, this.desc, this.publishedAt, this.source,
this.type, this.url, this.used, this.who);
@override
String toString() {
return 'FLModle{_id: $_id, createdAt: $createdAt, desc: $desc, publishedAt: $publishedAt, source: $source, type: $type, url: $url, used: $used, who: $who}';
}
FLModle.fromJson(Map<String, dynamic> json)
: _id = json['_id'],
createdAt = json['createdAt'],
desc = json['desc'],
publishedAt = json['publishedAt'],
source = json['source'],
type = json['publishedAt'],
url = json['url'],
used = json['used'],
who = json['who'];
}
第二步:
創(chuàng)建一個有狀態(tài)的組件,繼承StatefulWidget,在createState方法中創(chuàng)建我們繼承State的組件。
class MeziList extends StatefulWidget{
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return new MeziSateList();
}
}
第三步:創(chuàng)建MeziSateList,繼承State組件,可通過setState來更新UI,相當于Android中的runOnUI
(此處內(nèi)代碼放在最后一步編寫)。
class MeziSateList extends State<MeziList>{
@override
Widget build(BuildContext context) {
// TODO: implement build
}
}
第四步:
構(gòu)建網(wǎng)絡(luò)請求,返回需要的List集合,使用async和await來完成耗時的操作,相當關(guān)android中的子線程,F(xiàn)uture類似于消息機制(個人觀點,只是為了簡單理解):
Future<List<FLModle>> _getDate(int pageNum,int pageSize) async{
List flModels;
String url = Constant.baseUrl + '福利/$pageSize/$pageNum';
print(url);
Response response = await dio.get(url);
if(response.statusCode== HttpStatus.OK){//響應(yīng)成功
flModels = (response.data)['results'] ;
currentpage = currentpage+1;//加載成功后才可加載下一頁
}else{//出問題
}
print(flModels.map((model) {
return new FLModle.fromJson(model);
}).toList().length);
return flModels.map((model) {
return new FLModle.fromJson(model);
}).toList();
}
Future<List<FLModle>> feach(int pageNum,int pageSize){
return _getDate(pageNum, pageSize);
}
第四步:編寫加載更多和刷新各自對應(yīng)的邏輯
//刷新時調(diào)用
Future<Null> _refreshData(){
final Completer<Null> completer = new Completer<Null>();
currentpage = 1;
feach(currentpage, pageSize).then((list) {
setState(() {
datas = list;
});
}).catchError((error) {
print(error);
});
completer.complete(null);
return completer.future;
}
//加載更多時調(diào)用
Future<Null> _loadMoreData(){
final Completer<Null> completer = new Completer<Null>();
feach(currentpage, pageSize).then((list) {
setState(() {
datas.addAll(list);
});
}).catchError((error) {
print(error);
});
completer.complete(null);
return completer.future;
}
第五步:
創(chuàng)建ScrollController來監(jiān)聽ListView的滑動,需要在initState方法中addListener,并且在dispose中removeListener。
/滑動到底了自動加載更多
void _scrollListener(){
if(_scrollController.position.pixels==_scrollController.position.maxScrollExtent){
_loadMoreData();
}
}
//頁面初始化時加載數(shù)據(jù)并實例化ScrollController
@override
void initState() {
// TODO: implement initState
super.initState();
_refreshData();
_scrollController = new ScrollController()..addListener(_scrollListener);
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
_scrollController.removeListener(_scrollListener);
}
第六步:
創(chuàng)建item并實現(xiàn)點擊事件
Widget buildCardItem(BuildContext context,int index){
final String url = datas[index].url;
return new GestureDetector(//點擊事件
onTap: (){
_showPhoto(url);
},
child: new Card(
child: new Container(
padding: EdgeInsets.all(8.0),
child: new Image.network(url),
),
),
);
}
最后一步:
構(gòu)建ListView,數(shù)據(jù)加載時顯示圓環(huán)
@override
Widget build(BuildContext context) {
// TODO: implement build
var content ;
if(datas.isEmpty){
content = new Center(child: new CircularProgressIndicator());;
}else{
content = new ListView.builder(
physics: AlwaysScrollableScrollPhysics(),
itemCount: datas.length,
controller: _scrollController,
itemBuilder: buildCardItem,
);
}
var _refreshIndicator = new RefreshIndicator(
onRefresh: _refreshData,
child: content,
);
return _refreshIndicator;
}
完整代碼
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'progreess_dialog.dart';
import 'package:easy_app/multi_touch_page.dart';
import 'constant.dart';
//解析類
class FLModle{
final String _id;
final String createdAt;
final String desc;
final String publishedAt;
final String source;
final String type;
final String url;
final bool used;
final String who;
const FLModle(this._id, this.createdAt, this.desc, this.publishedAt, this.source,
this.type, this.url, this.used, this.who);
@override
String toString() {
return 'FLModle{_id: $_id, createdAt: $createdAt, desc: $desc, publishedAt: $publishedAt, source: $source, type: $type, url: $url, used: $used, who: $who}';
}
FLModle.fromJson(Map<String, dynamic> json)
: _id = json['_id'],
createdAt = json['createdAt'],
desc = json['desc'],
publishedAt = json['publishedAt'],
source = json['source'],
type = json['publishedAt'],
url = json['url'],
used = json['used'],
who = json['who'];
}
class TabGirlPage extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return new Scaffold(
body: new MeziList(),
);
}
}
class MeziList extends StatefulWidget{
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return new MeziSateList();
}
}
class MeziSateList extends State<MeziList>{
List<FLModle> datas = [];//初始化列表數(shù)據(jù)源
int currentpage = 1;//默認當前頁
int pageSize = 10;//每頁加載數(shù)據(jù)
Dio dio = new Dio();//第三方網(wǎng)絡(luò)加載庫
ScrollController _scrollController;
//滑動到底了自動加載更多
void _scrollListener(){
if(_scrollController.position.pixels==_scrollController.position.maxScrollExtent){
_loadMoreData();
}
}
//頁面初始化時加載數(shù)據(jù)并實例化ScrollController
@override
void initState() {
// TODO: implement initState
super.initState();
_refreshData();
_scrollController = new ScrollController()..addListener(_scrollListener);
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
_scrollController.removeListener(_scrollListener);
}
@override
Widget build(BuildContext context) {
// TODO: implement build
var content ;
if(datas.isEmpty){
content = new Center(child: new CircularProgressIndicator());;
}else{
content = new ListView.builder(
physics: AlwaysScrollableScrollPhysics(),
itemCount: datas.length,
controller: _scrollController,
itemBuilder: buildCardItem,
);
}
var _refreshIndicator = new RefreshIndicator(
onRefresh: _refreshData,
child: content,
);
return _refreshIndicator;
}
void _showPhoto(String url) {
Navigator.of(context).push(new PageRouteBuilder(
opaque: false,
pageBuilder: (BuildContext context, _, __) {
return new MultiTouchPage(url);
},
transitionsBuilder: (_, Animation<double> animation, __, Widget child) {
return new FadeTransition(
opacity: animation,
child: new RotationTransition(
turns: new Tween<double>(begin: 0.5, end: 1.0).animate(animation),
child: child,
),
);
}));
}
Widget buildCardItem(BuildContext context,int index){
final String url = datas[index].url;
return new GestureDetector(//點擊事件
onTap: (){
_showPhoto(url);
},
child: new Card(
child: new Container(
padding: EdgeInsets.all(8.0),
child: new Image.network(url),
),
),
);
}
//刷新時調(diào)用
Future<Null> _refreshData(){
final Completer<Null> completer = new Completer<Null>();
currentpage = 1;
feach(currentpage, pageSize).then((list) {
setState(() {
datas = list;
});
}).catchError((error) {
print(error);
});
completer.complete(null);
eturn completer.future;
}
//加載更多時調(diào)用
Future<Null> _loadMoreData(){
final Completer<Null> completer = new Completer<Null>();
feach(currentpage, pageSize).then((list) {
setState(() {
datas.addAll(list);
});
}).catchError((error) {
print(error);
});
completer.complete(null);
return completer.future;
}
Future<List<FLModle>> feach(int pageNum,int pageSize){
return _getDate(pageNum, pageSize);
}
Future<List<FLModle>> _getDate(int pageNum,int pageSize) async{
List flModels;
String url = Constant.baseUrl + '福利/$pageSize/$pageNum';
print(url);
Response response = await dio.get(url);
if(response.statusCode== HttpStatus.OK){//響應(yīng)成功
flModels = (response.data)['results'] ;
currentpage = currentpage+1;//加載成功后才可加載下一頁
}else{//出問題
}
print(flModels.map((model) {
return new FLModle.fromJson(model);
}).toList().length);
return flModels.map((model) {
return new FLModle.fromJson(model);
}).toList();
}
}