flutter for web:在显示之前从 NetworkImage 获取 width/height
flutter for web: Get width/height form NetworkImage before displaying it
我想在显示图像之前从 NetworkImage
或 Image.network
获取属性值,例如宽度和高度。
我找到了以下好帖子,但是没有用。它获得了大小值,但图像未加载 FutureBuilder
。
我的代码如下;
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: FutureBuilder(
future: _getImage(),
builder: (BuildContext context, AsyncSnapshot<Image> snapshot) {
print(snapshot.hasData);
if (snapshot.hasData) {
return snapshot.data;
} else {
return Text('Loading...');
}
},
),
),
);
}
Future<Image> _getImage() async {
final Completer completer = Completer();
final String url = 'http://images-jp.amazon.com/images/P/4101098018.09.MZZZZZZZ';
final image = NetworkImage(url);
image.resolve(ImageConfiguration())
.addListener(ImageStreamListener((ImageInfo info, bool isSync) {
print(info.image.width);
completer.complete(info.image);
}));
return completer.future;
}
}
结果是;
- 屏幕仅显示 "Loading..." 并且未加载图像。
- print
输出如下。这应该意味着, FutureBuilder
在加载图像之前被调用了两次,我们可以得到宽度,但之后 FutureBuilder
没有被调用。
false
false
112
环境:
- Flutter 1.13.0 • 频道开发(由于 flutter web)
- Chrome 版本 79.0.3945.79
在Abion47的指点下,我通过http包成功获取了镜像。但是即使在获取图像后我仍然无法获取宽度和/或高度值。
或者,我使用 response.body.length
检查下载的图像是否有效。
Future<Image> _getImage() async {
Image _image;
final String url = 'http://images-jp.amazon.com/images/P/4101098018.09.MZZZZZZZ';
var response = await http.get(url);
print("Response status: ${response.statusCode}"); // 200
_image = Image.memory(response.bodyBytes);
print(_image.width); // still null
print(response.body.length); // this shows numbers. I'll use this.
return _image;
}
根据您提供的参考 post 进行的一些观察。
- 您混淆了
ui.Image
和 Image
小部件。
- 如果您将信息逻辑与小部件构建分开,那么您将无法访问图像小部件,这意味着您将不得不重新创建它。相反,您可以创建一个小部件并 return 它。
- 在您基于
http
的答案中,response.body.length
可能不完全代表图像尺寸。您必须查看响应 headers 是否包含有关图像的任何信息。
- 另请注意,
FutureBuilder
的构建方法将根据 waiting
或 done
等未来状态以不同的 ConnectionState
多次调用。检查 here
选项 1:
如果您不关心 Image 小部件,那么您当前的代码只需稍作修改即可使用。这与原始 post 完全相同,但经过修改以匹配您在 post.
中定义它的方式
import 'dart:async';
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
class ImageSizeTestWidget extends StatefulWidget {
ImageSizeTestWidget({Key key, this.title}) : super(key: key);
final String title;
@override
_ImageSizeTestWidgetState createState() => _ImageSizeTestWidgetState();
}
class _ImageSizeTestWidgetState extends State<ImageSizeTestWidget> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: FutureBuilder<ui.Image>(
future: _getImage(),
builder: (BuildContext context, AsyncSnapshot<ui.Image> snapshot) {
print(snapshot.hasData);
if (snapshot.hasData) {
return Text('${snapshot.data.width} X ${snapshot.data.height}');
} else {
return Text('Loading...');
}
},
),
),
);
}
Future<ui.Image> _getImage() async {
final Completer<ui.Image> completer = Completer<ui.Image>();
final String url =
'http://images-jp.amazon.com/images/P/4101098018.09.MZZZZZZZ';
Image image = Image.network(url);
image.image
.resolve(ImageConfiguration())
.addListener(ImageStreamListener((ImageInfo info, bool isSync) {
print(info.image.width);
completer.complete(info.image);
}));
return completer.future;
}
}
选项 2:
只需使用原始 post 中的代码,将图像小部件的创建和信息提取引入构建方法。
您已经完成了自我回答代码的一半。从那里,您可以使用 instantiateImageCodec
.
将字节转换为 ui.Image
对象
Future<Image> _getImage() async {
Image _image;
final String url = 'http://images-jp.amazon.com/images/P/4101098018.09.MZZZZZZZ';
var response = await http.get(url);
print("Response status: ${response.statusCode}"); // 200, ideally
final bytes = response.bodyBytes);
final codec = await instantiateImageCodec(bytes);
final frame = await codec.getNextFrame();
final uiImage = frame.image; // a ui.Image object, not to be confused with the Image widget
print(uiImage.width); // The width of the image in pixels
print(uiImage.height); // The heightof the image in pixels
_image = Image.memory(bytes);
return _image;
}
你必须这样做有点糟糕,因为图像将被解码两次,但还没有创建你自己的可以直接获取 ui.Image
对象的自定义 Image
小部件,我认为对此无能为力。
我想在显示图像之前从 NetworkImage
或 Image.network
获取属性值,例如宽度和高度。
我找到了以下好帖子,但是没有用。它获得了大小值,但图像未加载 FutureBuilder
。
我的代码如下;
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: FutureBuilder(
future: _getImage(),
builder: (BuildContext context, AsyncSnapshot<Image> snapshot) {
print(snapshot.hasData);
if (snapshot.hasData) {
return snapshot.data;
} else {
return Text('Loading...');
}
},
),
),
);
}
Future<Image> _getImage() async {
final Completer completer = Completer();
final String url = 'http://images-jp.amazon.com/images/P/4101098018.09.MZZZZZZZ';
final image = NetworkImage(url);
image.resolve(ImageConfiguration())
.addListener(ImageStreamListener((ImageInfo info, bool isSync) {
print(info.image.width);
completer.complete(info.image);
}));
return completer.future;
}
}
结果是;
- 屏幕仅显示 "Loading..." 并且未加载图像。
- print
输出如下。这应该意味着, FutureBuilder
在加载图像之前被调用了两次,我们可以得到宽度,但之后 FutureBuilder
没有被调用。
false
false
112
环境:
- Flutter 1.13.0 • 频道开发(由于 flutter web)
- Chrome 版本 79.0.3945.79
在Abion47的指点下,我通过http包成功获取了镜像。但是即使在获取图像后我仍然无法获取宽度和/或高度值。
或者,我使用 response.body.length
检查下载的图像是否有效。
Future<Image> _getImage() async {
Image _image;
final String url = 'http://images-jp.amazon.com/images/P/4101098018.09.MZZZZZZZ';
var response = await http.get(url);
print("Response status: ${response.statusCode}"); // 200
_image = Image.memory(response.bodyBytes);
print(_image.width); // still null
print(response.body.length); // this shows numbers. I'll use this.
return _image;
}
根据您提供的参考 post 进行的一些观察。
- 您混淆了
ui.Image
和Image
小部件。 - 如果您将信息逻辑与小部件构建分开,那么您将无法访问图像小部件,这意味着您将不得不重新创建它。相反,您可以创建一个小部件并 return 它。
- 在您基于
http
的答案中,response.body.length
可能不完全代表图像尺寸。您必须查看响应 headers 是否包含有关图像的任何信息。 - 另请注意,
FutureBuilder
的构建方法将根据waiting
或done
等未来状态以不同的ConnectionState
多次调用。检查 here
选项 1: 如果您不关心 Image 小部件,那么您当前的代码只需稍作修改即可使用。这与原始 post 完全相同,但经过修改以匹配您在 post.
中定义它的方式import 'dart:async';
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
class ImageSizeTestWidget extends StatefulWidget {
ImageSizeTestWidget({Key key, this.title}) : super(key: key);
final String title;
@override
_ImageSizeTestWidgetState createState() => _ImageSizeTestWidgetState();
}
class _ImageSizeTestWidgetState extends State<ImageSizeTestWidget> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: FutureBuilder<ui.Image>(
future: _getImage(),
builder: (BuildContext context, AsyncSnapshot<ui.Image> snapshot) {
print(snapshot.hasData);
if (snapshot.hasData) {
return Text('${snapshot.data.width} X ${snapshot.data.height}');
} else {
return Text('Loading...');
}
},
),
),
);
}
Future<ui.Image> _getImage() async {
final Completer<ui.Image> completer = Completer<ui.Image>();
final String url =
'http://images-jp.amazon.com/images/P/4101098018.09.MZZZZZZZ';
Image image = Image.network(url);
image.image
.resolve(ImageConfiguration())
.addListener(ImageStreamListener((ImageInfo info, bool isSync) {
print(info.image.width);
completer.complete(info.image);
}));
return completer.future;
}
}
选项 2: 只需使用原始 post 中的代码,将图像小部件的创建和信息提取引入构建方法。
您已经完成了自我回答代码的一半。从那里,您可以使用 instantiateImageCodec
.
ui.Image
对象
Future<Image> _getImage() async {
Image _image;
final String url = 'http://images-jp.amazon.com/images/P/4101098018.09.MZZZZZZZ';
var response = await http.get(url);
print("Response status: ${response.statusCode}"); // 200, ideally
final bytes = response.bodyBytes);
final codec = await instantiateImageCodec(bytes);
final frame = await codec.getNextFrame();
final uiImage = frame.image; // a ui.Image object, not to be confused with the Image widget
print(uiImage.width); // The width of the image in pixels
print(uiImage.height); // The heightof the image in pixels
_image = Image.memory(bytes);
return _image;
}
你必须这样做有点糟糕,因为图像将被解码两次,但还没有创建你自己的可以直接获取 ui.Image
对象的自定义 Image
小部件,我认为对此无能为力。