[英]How to use future inside a list in Flutter?
我正在尝试从网络加载图像,而不是将其作为完成的将来Image
传递给ExtendedRawImage进行裁剪。
问题在于,每个传入的新映像都使用(我认为)Future的同一实例来检查映像是否已加载,这就是为什么在每个新映像上都显示CircularProgressIndicator
的原因。
我尝试过 但无法解决问题的事情:
StatefulWidget
小部件。 我现在正在使用的代码和gif:
AnimatedList(
key: _sListKey,
physics: BouncingScrollPhysics(),
controller: _sScrollCtrl,
padding: EdgeInsets.all(5),
initialItemCount: sData.length,
itemBuilder: (context, index, animation) {
final vehicle = sData[index];
final color = defaultRegions.contains(vehicle.region)
? Colors.grey
: Colors.blue;
return _dataContainer(
vehicle, animation);
},
)
class CropImage extends StatefulWidget {
final Vehicle vehicle;
CropImage({Key key, this.vehicle}) : super(key: key);
@override
_CropImageState createState() => _CropImageState();
}
class _CropImageState extends State<CropImage> {
Future<ImageInfo> _imageInfo;
@override
void initState() {
super.initState();
NetworkImage image = NetworkImage(widget.vehicle.image);
Completer<ImageInfo> completer = Completer();
image
.resolve(new ImageConfiguration())
.addListener(ImageStreamListener((ImageInfo info, bool _) {
completer.complete(info);
}));
_imageInfo = completer.future;
}
@override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: widget.vehicle.vehicleRegion.width /
widget.vehicle.vehicleRegion.height,
child: FutureBuilder(
// key: UniqueKey(),
future: _imageInfo,
builder: (context, AsyncSnapshot<ImageInfo> snapshot) {
if (snapshot.hasData) {
return ExtendedRawImage(
image: snapshot.data.image,
fit: BoxFit.cover,
soucreRect: Rect.fromLTWH(
widget.vehicle.vehicleRegion.x,
widget.vehicle.vehicleRegion.y,
widget.vehicle.vehicleRegion.width,
widget.vehicle.vehicleRegion.height,
),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
),
);
}
}
UPDATE_1 : _dataContainer()
包含我用常规Container包装的CropImage
小部件。 另外请注意,我正在使用websocket通过将数据使用_sListKey.currentState.insertItem(0)
插入列表顶部来将数据传递给AnimatedList
。
UPDATE_2我认为我已经缩小了范围。 如果我在AnimatedList
使用任何一种FutureBuilder
(如下所示),它将产生相同的问题(添加“键”或移至其他Statefull
小部件不能解决问题)。
FutureBuilder(
future: http.get(vehicle.image),
builder: (context, AsyncSnapshot<http.Response> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Image.memory(snapshot.data.bodyBytes);
} else {
return CircularProgressIndicator();
}
},
),
UPDATE_3 :它表明核心问题来自setState()
调用。 因为我正在使用weboskcet
将数据传递给视图,所以每次有新数据传入时,都会调用setState()
来通知AnimatedList
或Listview
重新加载视图,这将强制FutureBuilder
刷新。 但是知道这并不能解决我的问题。
@override
void initState() {
super.initState();
ws.dataCallback = (vehicle, status) {
switch (status) {
case 0:
setState(() {});
break;
}
};
}
注意 :根据要求,创建了我的问题的示例存储库( 链接到repo )。
请参阅FutureBuilder的文档: https ://api.flutter.dev/flutter/widgets/FutureBuilder-class.html
将来必须早一点获得,例如在State.initState,State.didUpdateConfig或State.didChangeDependencies中。 构造FutureBuilder时,不得在State.build或StatelessWidget.build方法调用期间创建它。 如果Future与FutureBuilder同时创建,则每次FutureBuilder的父代重建时,异步任务都将重新启动。
您可以通过将FutureBuilder包装在自己的StatefulWidget中并在initState中调用fetchImage并将其分配给字段来解决此问题。
编辑:如果即使在initState方法内部完成加载,如果所有图像仍在重新加载,则必须表示State对象正在重新初始化。 假设您提到要在开始时添加项目,则您的问题可能与以下问题https://github.com/flutter/flutter/issues/21023#issuecomment-510950338有关 。 提到ListView.builder不支持列表中的更改,因为它使用索引进行跟踪。 尽管问题与ListView.builder有关,但是AnimatedList文档提到:
此小部件类似于[ListView.builder]创建的小部件。
如果您唯一的要求是在顶部插入项目,则可以考虑将项目添加到末尾并使用相反的rinkWrap AnimatedList。 一个最小的例子:
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Example(),
);
}
}
class Example extends StatefulWidget {
@override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
List<Vehicle> vehicles = new List();
GlobalKey<AnimatedListState> listKey = GlobalKey<AnimatedListState>();
Random rng = new Random();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: AnimatedList(
shrinkWrap: true,
reverse: true,
key: listKey,
initialItemCount: vehicles.length,
itemBuilder: (context, index, animation) => SizeTransition(
axis: Axis.vertical,
sizeFactor: animation,
child: ListTile(
title: WidgetWithFutureBuilder('${vehicles[index].name}'),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
int id = rng.nextInt(5000);
vehicles.add(new Vehicle(name: "Vehicle $id"));
listKey.currentState.insertItem(vehicles.length - 1);
});
},
),
);
}
}
class WidgetWithFutureBuilder extends StatefulWidget {
final String name;
WidgetWithFutureBuilder(this.name);
@override
_WidgetWithFutureBuilderState createState() =>
_WidgetWithFutureBuilderState();
}
class _WidgetWithFutureBuilderState extends State<WidgetWithFutureBuilder> {
Future<String> future;
@override
void initState() {
super.initState();
this.future = Future.delayed(Duration(seconds: 1), () => widget.name);
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: future,
builder: (context, state) {
if (state.hasData) {
return ListTile(
title: Text(state.data),
);
}
return Center(child: CircularProgressIndicator());
},
);
}
}
class Vehicle {
Vehicle({this.name});
String name;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.