有限滚动
解决方案很简单,您只需将itemCount 添加到构建器,以便构建器允许它知道项目数。就像上面的代码一样this answer
无限滚动
要进行无限滚动,请使用 ListView.builder 而不指定 itemCount 参数。
body: ListView.builder(
itemCount: _photos.length + (_hasMore ? 1 : 0),
itemBuilder: (context, index) {
if (index == item.length - _nextPageThreshold) {
// Here is your manuplated data code
} else {
getMoreData();
return Center(child: CircularProgressIndicator());
}
},
),
完整代码示例
class ItemListScreen extends StatefulWidget {
ItemListScreen({Key key}) : super(key: key);
@override
_PhotosListScreenState createState() => _PhotosListScreenState();
}
class _PhotosListScreenState extends State<ItemListScreen> {
bool _hasMore;
int _pageNumber;
bool _error;
bool _loading;
final int _defaultPhotosPerPageCount = 10;
List<Photo> _photos;
final int _nextPageThreshold = 5;
@override
void initState() {
super.initState();
_hasMore = true;
_pageNumber = 1;
_error = false;
_loading = true;
_photos = [];
fetchPhotos();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Photos App")),
body: getBody(),
);
}
Widget getBody() {
if (_photos.isEmpty) {
if (_loading) {
return Center(
child: Padding(
padding: const EdgeInsets.all(8),
child: CircularProgressIndicator(),
));
} else if (_error) {
return Center(
child: InkWell(
onTap: () {
setState(() {
_loading = true;
_error = false;
fetchPhotos();
});
},
child: Padding(
padding: const EdgeInsets.all(16),
child: Text("Error while loading photos, tap to try agin"),
),
));
}
} else {
return ListView.builder(
itemCount: _photos.length + (_hasMore ? 1 : 0),
itemBuilder: (context, index) {
if (index == _photos.length - _nextPageThreshold) {
fetchPhotos();
}
if (index == _photos.length) {
if (_error) {
return Center(
child: InkWell(
onTap: () {
setState(() {
_loading = true;
_error = false;
fetchPhotos();
});
},
child: Padding(
padding: const EdgeInsets.all(16),
child: Text("Error while loading photos, tap to try agin"),
),
));
} else {
return Center(
child: Padding(
padding: const EdgeInsets.all(8),
child: CircularProgressIndicator(),
));
}
}
final Photo photo = _photos[index];
return Card(
child: Column(
children: <Widget>[
Image.network(
photo.thumbnailUrl,
fit: BoxFit.fitWidth,
width: double.infinity,
height: 160,
),
Padding(
padding: const EdgeInsets.all(16),
child: Text(photo.title,
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 16)),
),
],
),
);
});
}
return Container();
}
Future<void> fetchPhotos() async {
try {
final response = await http.get("https://jsonplaceholder.typicode.com/photos?_page=$_pageNumber");
List<Photo> fetchedPhotos = Photo.parseList(json.decode(response.body));
setState(() {
_hasMore = fetchedPhotos.length == _defaultPhotosPerPageCount;
_loading = false;
_pageNumber = _pageNumber + 1;
_photos.addAll(fetchedPhotos);
});
} catch (e) {
setState(() {
_loading = false;
_error = true;
});
}
}
}
class Photo {
final String title;
final String thumbnailUrl;
Photo(this.title, this.thumbnailUrl);
factory Photo.fromJson(Map<String, dynamic> json) {
return Photo(json["title"], json["thumbnailUrl"]);
}
static List<Photo> parseList(List<dynamic> list) {
return list.map((i) => Photo.fromJson(i)).toList();
}
}
无限滚动答案信用和更多信息Infinite Scrolling ListView