在这种情况下,如何在 Flutter 中正确实现 FutureBuilder?
Posted
技术标签:
【中文标题】在这种情况下,如何在 Flutter 中正确实现 FutureBuilder?【英文标题】:How do I correctly implement a FutureBuilder in Flutter in this case? 【发布时间】:2021-08-17 18:09:52 【问题描述】:我正在尝试显示不同图像的水平可滚动 ListView。这应该通过 Widget MultipleImageDemo 来实现。我在 loadAssets() 中使用 MultipleImagePicker 来创建从 iPhone 库中选择的图像的资产列表。然后,我将这些资产转换为文件,以便我可以使用来自How to convert asset image to File? 的 getImageFileFromAssets(Asset asset) 在 ListView 中显示它们。但是,将资产转换为文件的函数是异步的,因此当我尝试在 Widget 构建(BuildContext 上下文)中使用此函数时,我需要使用 FutureBuilder。
这就是我尝试实现它的方式:
Future<File> getImageFileFromAssets(Asset asset) async
final byteData = await asset.getByteData();
final tempFile =
File("$(await getTemporaryDirectory()).path/$asset.name");
final file = await tempFile.writeAsBytes(
byteData.buffer.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes),
);
class MultipleImageDemo extends StatefulWidget
@override
_MultipleImageDemoState createState() => _MultipleImageDemoState();
class _MultipleImageDemoState extends State<MultipleImageDemo>
List<Asset> images = <Asset>[];
@override
void initState()
super.initState();
Future<ListView> DisplayPhotos() async
List<File> displayedPhotos = <File>[];
for (var i = 0; i < images.length; i++)
File image_file = await getImageFileFromAssets(images[i]);
displayedPhotos.add(image_file);
return ListView(
scrollDirection: Axis.horizontal,
children: List.generate(displayedPhotos.length, (index)
File displayedPhoto = displayedPhotos[index];
return Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Image.file(displayedPhoto));
));
Future<void> loadAssets() async
List<Asset> resultList = <Asset>[];
String error = 'No Error Detected';
try
resultList = await MultiImagePicker.pickImages(
maxImages: 300,
enableCamera: true,
selectedAssets: images,
cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"),
materialOptions: MaterialOptions(
actionBarColor: "#abcdef",
actionBarTitle: "Example App",
allViewTitle: "All Photos",
useDetailsView: false,
selectCircleStrokeColor: "#000000",
),
);
on Exception catch (e)
error = e.toString();
if (!mounted) return;
setState(()
images = resultList;
// _error = error;
);
@override
Widget build(BuildContext context)
return Scaffold(
body: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
child: Text("Pick images"),
onPressed: loadAssets,
),
Expanded(
child: FutureBuilder<ListView>(
future: DisplayPhotos(),
builder: (BuildContext context,
AsyncSnapshot<ListView> snapshot)
List<Widget> children;
if (snapshot.hasData)
children = <Widget>[
const Icon(
Icons.check_circle_outline,
color: Colors.green,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Result: $snapshot.data'),
)
];
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: children,
),
);
)),
],
),
),
);
这是我得到的错误:
The following assertion was thrown building FutureBuilder<ListView>(dirty, state: _FutureBuilderState<ListView>#66af4):
'package:flutter/src/widgets/framework.dart': Failed assertion: line 1741 pos 14: 'children != null': is not true.
2
Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
https://github.com/flutter/flutter/issues/new?template=2_bug.md
The relevant error-causing widget was
FutureBuilder<ListView>
package:project_startup/screens/addPage.dart:279
When the exception was thrown, this was the stack
#2 new MultiChildRenderObjectWidget
package:flutter/…/widgets/framework.dart:1741
#3 new Flex
package:flutter/…/widgets/basic.dart:4371
#4 new Column
package:flutter/…/widgets/basic.dart:4939
#5 _MultipleImageDemoState.build.<anonymous closure>
package:project_startup/screens/addPage.dart:323
#6 _FutureBuilderState.build
package:flutter/…/widgets/async.dart:775
如何正确实现 FutureBuilder?有必要用吗?
This is what is the simulator shows when I run this app even after I have selected several images from the gallery
【问题讨论】:
【参考方案1】:编辑
要显示图像,您可以执行以下操作:
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [snapshot.data, ...children], // this line
),
);
将List<Widget> children;
更改为List<Widget> children = [];
,这样它就被初始化了。
问题出在这个:
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: children, // this line
),
);
因为在加载快照时children
为空(没有数据),您会在控制台中看到该错误。
【讨论】:
感谢您的回答,但是,我试过了,模拟器仍然没有显示我在图库中选择的图像,尽管幸运的是错误现在已经消失了!你看到其他问题了吗?如何使 DisplayPhotos() 返回的 ListView 显示出来? 你能传递 snapshot.data 而不是 children 吗?返回中心(子:列(mainAxisAlignment:MainAxisAlignment.center,crossAxisAlignment:CrossAxisAlignment.center,子:snapshot.data,),) @Andrija 我同意,这是有道理的,但这样做会产生以下错误:The argument type 'ListView' can't be assigned to the parameter type 'List<Widget>'.
你看到我可以返回 snapshot.data 而不是孩子的不同方式吗?
@JohannLeidenfrost 我已经编辑了我的答案。【参考方案2】:
将snapshot.data
插入children
然后在返回的容器中显示孩子似乎已经解决了这个问题。非常感谢帮助过的人:)。
Widget build(BuildContext context)
return Scaffold(
body: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
child: Text(PICKIMAGES),
onPressed: loadAssets,
),
Expanded(
child: FutureBuilder<Container>(
future: DisplayPhotos(),
builder: (BuildContext context,
AsyncSnapshot<Container> snapshot)
List<Widget> children = [];
if (snapshot.hasData)
children = <Widget>[
snapshot.data,
];
return Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: ListView(
children: children));
)),
],
),
),
);
【讨论】:
以上是关于在这种情况下,如何在 Flutter 中正确实现 FutureBuilder?的主要内容,如果未能解决你的问题,请参考以下文章