我是新来的人。我一直在尝试操作我的代码来刷新从其他API获取的内容列表。我注意到在触发RefreshIndicator()
时正在加载新内容,但是全新内容被放置在先前加载的内容之下。请帮忙。我的完整代码如下。
我需要什么;刷新API,如果找到新内容,则应将其放在顶部并覆盖以前的内容,
import 'dart:convert';
import 'dart:io';
import 'dart:async';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:timeago/timeago.dart';
import 'package:flutter/material.dart';
import 'about.dart';
import 'fetchposts.dart';
import 'post.dart';
import 'post_details.dart';
import 'strings.dart';
import 'package:http/http.dart' as http;
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
enum IndicatorType { overscroll , refresh }
class _MyHomePageState extends State<MyHomePage> {
bool _isRequestSent = false;
bool _isRequestFailed = false;
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey = new GlobalKey<RefreshIndicatorState>();
List<Post> postList = [];
@override
void initState() {
super.initState();
_downloadData();
}
Future<Null> _handleRefresh() async {
final Completer<Null> completer = new Completer<Null>();
new Timer(const Duration(seconds: 3),() {completer.complete(null);});
return completer.future.then((_){
_downloadData();
_scaffoldKey.currentState?.showSnackBar(new SnackBar(
content: const Text('Refresh Complete'),
action: new SnackBarAction(
label: 'RETRY',
onPressed: () {
_refreshIndicatorKey.currentState.show();
},
)
));
});
}
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
key: _scaffoldKey,
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('Gossipper'),
decoration: BoxDecoration(color: Colors.white),
),
ListTile(
title: Text('Home'),
onTap: () {
Navigator.push(context,
MaterialPageRoute(
builder: (BuildContext context) => AboutUs()
),
);
},
),
ListTile(
title: Text('Forum'),
onTap: () {
},
),
],
),
),
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
backgroundColor: Colors.green,
centerTitle: true,
actions: <Widget>[
new IconButton(
icon: const Icon(Icons.refresh),
tooltip: 'Refresh',
onPressed: () {
_refreshIndicatorKey.currentState.show();
},
)
],
),
body: new Container(
alignment: Alignment.center,
child: !_isRequestSent
// Request has not been sent, let's show a progress indicator
? new CircularProgressIndicator(backgroundColor: Colors.green,)
// Request has been sent but did it fail?
: _isRequestFailed
// Yes, it has failed. Show a retry UI
? _showRetryUI()
// No it didn't fail. Show the data
: new RefreshIndicator(
key: _refreshIndicatorKey,
onRefresh: _handleRefresh,
child: new Container(
child: ListView.builder(
itemCount: postList.length,
scrollDirection: Axis.vertical,
padding: EdgeInsets.all(8.0),
itemBuilder: (BuildContext context, int index) {
return _getPostWidgets(index);
}),
),
),
),
);
}
Widget _getPostWidgets(int index) {
var post = postList[index];
return new GestureDetector(
onTap: () {
openDetailsUI(post);
},
child: new Container(
margin: const EdgeInsets.symmetric(horizontal: 5.0, vertical: 5.0),
child: new Card(
elevation: 3.0,
child: new Row(
children: <Widget>[
new Container(
width: 150.0,
child: new CachedNetworkImage(
imageUrl: post.thumbUrl,
fit: BoxFit.cover,
placeholder: new Icon(
Icons.panorama,
color: Colors.grey,
size: 120.0,
),
),
),
new Expanded(
child: new Container(
margin: new EdgeInsets.all(10.0),
child: new Text(
post.title,
style: new TextStyle(color: Colors.black, fontSize: 18.0),
),
)),
],
),
),
),
);
}
void _downloadData() {
MyHttpCall.getData().then((jsonData) {
if(jsonData["results"] != null) {
for (var jsonObject in jsonData["results"]) {
var post = Post.getPostFrmJSONPost(jsonObject);
postList.add(post);
print(post);
}
setState(() => _isRequestSent = true);
}
}
);
}
void handleRequestError() {
setState(() {
_isRequestSent = true;
_isRequestFailed = true;
});
}
Widget _showRetryUI() {
return new Container(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
Strings.requestFailed,
style: new TextStyle(fontSize: 16.0),
),
new Padding(
padding: new EdgeInsets.only(top: 10.0),
child: new RaisedButton(
onPressed: retryRequest,
child: new Text(
Strings.retry,
style: new TextStyle(color: Colors.white),
),
color: Theme.of(context).accentColor,
splashColor: Colors.deepOrangeAccent,
),
)
],
),
);
}
void retryRequest() {
setState(() {
// Let's just reset the fields.
_isRequestSent = false;
_isRequestFailed = false;
});
}
openDetailsUI(Post post) {
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) => new PostDetails(post)));
}
}