如何在Flutter中从http服务器构建动态列表? [英] how to build dynamic list from http server in flutter?
问题描述
Flutter新手,从这里学到了很多东西。
Flutter newbie, learned a lot from here.
在通常情况下,人们会从Web服务器请求资源,服务器会返回对象数组:
In a common case, people will request resource from web servers and server return an array of objects:
[ { "key": "value"}, {"key": "value}...]
我们可以轻松地使用FutureBuilder。
We can easily handle this use FutureBuilder.
但是我有一台拥有海量数据的服务器,我必须从中获取资源方式:
But I have a server with massive data which I have to get resource in this way:
- 使用api查询记录计数,说 / resources / counts
- 查询用api记录几条记录,说 / resource?offset = 101& limit = 20以获得20条记录。
- 当用户向下滚动菜单时,将触发 / resource?offset = 121& limit = 20来获得另外20条记录。
所以我有一个列表,其中包含一些固定计数,但是资源有
So I have a list with fix count some kind, but the resource have to dynamic loaded from server. how to do that?
某些代码。
@override
Widget build(BuildContext context) {
// _max == -1, request in progress.
return _max == -1
? new CircularProgressIndicator()
: ListView.builder(
padding: const EdgeInsets.all(16.0),
itemBuilder: (context, i) {
return new FutureBuilder(
future: _getFollowingContracts(),
builder: (context, snapshot) {
if (i.isOdd) return new Divider();
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
case ConnectionState.active:
return new Text('loading...');
case ConnectionState.done:
if (i.isOdd)
return new Divider(
height: 2.0,
);
final int index = i ~/ 2;
// when user scroll down here we got exception
// because only 20 records is available.
// how to get another 20 records?
return _buildRow(_contracts[index]);
}
},
);
},
itemCount: _max * 2,
);
}
推荐答案
要实现此目的,您可以将 ScrollController
附加到 ListView
并监听其更改。在此侦听器中,当您处于滚动结尾时,您将获取更多数据并更新应用状态。
To implement this, you can attach a ScrollController
to your ListView
and listen its changes. In this listener when you are in the end of the scroll you fetch more data and update your app state.
示例:
以下代码是从这篇经充分说明的博客文章中提取的: https://marcinszalek.pl/flutter/infinite-dynamic-listview/ 。
The following code is extracted from this well explained blog post: https://marcinszalek.pl/flutter/infinite-dynamic-listview/.
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
theme: new ThemeData(primarySwatch: Colors.blue),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<int> items = List.generate(10, (i) => i);
ScrollController _scrollController = new ScrollController();
bool isPerformingRequest = false;
@override
void initState() {
super.initState();
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_getMoreData();
}
});
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
_getMoreData() async {
if (!isPerformingRequest) {
setState(() => isPerformingRequest = true);
List<int> newEntries = await fakeRequest(
items.length, items.length + 10); //returns empty list
if (newEntries.isEmpty) {
double edge = 50.0;
double offsetFromBottom = _scrollController.position.maxScrollExtent -
_scrollController.position.pixels;
if (offsetFromBottom < edge) {
_scrollController.animateTo(
_scrollController.offset - (edge - offsetFromBottom),
duration: new Duration(milliseconds: 500),
curve: Curves.easeOut);
}
}
setState(() {
items.addAll(newEntries);
isPerformingRequest = false;
});
}
}
Widget _buildProgressIndicator() {
return new Padding(
padding: const EdgeInsets.all(8.0),
child: new Center(
child: new Opacity(
opacity: isPerformingRequest ? 1.0 : 0.0,
child: new CircularProgressIndicator(),
),
),
);
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("Infinite ListView"),
),
body: ListView.builder(
itemCount: items.length + 1,
itemBuilder: (context, index) {
if (index == items.length) {
return _buildProgressIndicator();
} else {
return ListTile(title: new Text("Number $index"));
}
},
controller: _scrollController,
),
);
}
}
/// from - inclusive, to - exclusive
Future<List<int>> fakeRequest(int from, int to) async {
return Future.delayed(Duration(seconds: 2), () {
return List.generate(to - from, (i) => i + from);
});
}
您将不得不将此代码适应您的情况(主要是通过更改 fakeRequest
方法以及如何渲染图块),但我认为它将为您提供主要思想。
You will have to adapt this code to your scenario (mainly by changing the fakeRequest
method and how the tiles are rendered), but I think it will give you the main idea.
这篇关于如何在Flutter中从http服务器构建动态列表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!