gpt4 book ai didi

flutter - 如何在 Flutter 的列表中使用 future?

转载 作者:IT王子 更新时间:2023-10-29 07:15:08 24 4
gpt4 key购买 nike

我正在尝试从网络加载图像并将其传递给 ExtendedRawImage作为完成 future Image对其进行裁剪。

问题是每张新图片都使用(我认为)相同的 future 实例来检查图片是否已加载,这就是它显示 CircularProgressIndicator 的原因。在每张新图片上。

尝试没有解决我的问题的事情:

  • 为 future 添加关键,
  • 将功能移至全新的 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(),
);
}
},
),
);
}
}

enter image description here

UPDATE_1:_dataContainer()包含 CropImage我用常规容器包装的小部件。另请注意,我正在使用 websocket 将数据传递给 AnimatedList使用 _sListKey.currentState.insertItem(0) 将其插入列表顶部.

UPDATE_2 我想我已经缩小了问题范围。如果我使用任何一种 FutureBuilder里面AnimatedList (如下所示),它会产生同样的问题(添加“键”或移动到其他 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将数据传递给 View ,每次有新数据进来,setState()正在调用以通知 AnimatedListListview重新加载 View ,这会强制 FutureBuilder刷新。但知道这一点并不能解决我的问题。

@override
void initState() {
super.initState();

ws.dataCallback = (vehicle, status) {
switch (status) {
case 0:
setState(() {});
break;
}
};
}

注意:作为请求,创建了我的问题的示例存储库 (link to repo)。

最佳答案

请参阅 FutureBuilder 的文档:https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html

The future must have been obtained earlier, e.g. during State.initState, State.didUpdateConfig, or State.didChangeDependencies. It must not be created during the State.build or StatelessWidget.build method call when constructing the FutureBuilder. If the future is created at the same time as the FutureBuilder, then every time the FutureBuilder's parent is rebuilt, the asynchronous task will be restarted.

您可以通过将 FutureBuilder 包装在您自己的 StatefulWidget 中并调用 fetchImage 来解决这个问题,例如initState 并将其分配给一个字段。

编辑:如果所有图像仍然重新加载,即使加载是在 initState 方法内完成的,这一定意味着 State 对象正在重新初始化。鉴于您提到您将项目添加到开头,您的问题可能与以下问题有关 https://github.com/flutter/flutter/issues/21023#issuecomment-510950338 .提到 ListView.builder 不支持列表中的更改,因为它使用索引进行跟踪。虽然问题是关于 ListView.builder,但 AnimatedList 文档提到:

This widget is similar to one created by [ListView.builder].

如果您的唯一要求是将项目插入到顶部,您可以考虑将项目添加到末尾并使用反向 shrinkWrap 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;
}

关于flutter - 如何在 Flutter 的列表中使用 future?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57621792/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com