仅在视口内加载图像
Load image only if it's inside viewport
我有一个带有 ListView 的脚手架作为 child 可以滚动。
它的顶部有一个 header 容器和一个包含图像列表的列。
我只想在这些图像出现在视口中时加载这些图像,但所有图像都同时开始加载。
当我将这些图像添加到 ListView 的 children 时并没有发生这种情况,但我想将它们放到一个单独的小部件中以保持代码整洁。可能吗?
这是一个简化的例子:
const List<String> images = [
'https://cataas.com/cat?hash=1',
'https://cataas.com/cat?hash=2',
'https://cataas.com/cat?hash=3',
'https://cataas.com/cat?hash=4',
'https://cataas.com/cat?hash=5',
'https://cataas.com/cat?hash=6',
'https://cataas.com/cat?hash=7',
'https://cataas.com/cat?hash=8',
];
// Scaffold child
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView(
children: [
// Header
Placeholder(
fallbackHeight: 300,
),
Category(),
SizedBox(height: 16),
Category(),
],
);
}
}
class Category extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('Build category');
return Column(
children: [
Padding(
padding: EdgeInsets.all(32),
child: Text('CATEGORY TITLE'),
),
...images.map((image) => CategoryItem(image)),
],
);
}
}
class CategoryItem extends StatelessWidget {
final String imageUrl;
CategoryItem(this.imageUrl);
@override
Widget build(BuildContext context) {
print('Build image: $imageUrl');
return FadeInImage.memoryNetwork(
fit: BoxFit.cover,
placeholder: kTransparentImage,
image: imageUrl,
);
}
}
您需要使用 ListView.builder
,因为它会延迟渲染其子项。此外,您还需要使用一个列表。
问题是在加载之前您不知道图像的大小,因此所有高度为 0 的图像都会立即构建。但是,如果您为它们设置固定高度,它将按预期工作。
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
final children = [
// Header
Placeholder(
fallbackHeight: 300,
),
Padding(
padding: EdgeInsets.all(32),
child: Text('CATEGORY TITLE'),
),
...images.map((image) => CategoryItem(image)),
SizedBox(height: 16),
Padding(
padding: EdgeInsets.all(32),
child: Text('CATEGORY TITLE'),
),
...images.map((image) => CategoryItem(image)),
];
return Scaffold(
body: ListView.builder(
itemCount: children.length,
itemBuilder: (context, i) => children[i],
)
);
}
}
我有一个带有 ListView 的脚手架作为 child 可以滚动。 它的顶部有一个 header 容器和一个包含图像列表的列。
我只想在这些图像出现在视口中时加载这些图像,但所有图像都同时开始加载。
当我将这些图像添加到 ListView 的 children 时并没有发生这种情况,但我想将它们放到一个单独的小部件中以保持代码整洁。可能吗?
这是一个简化的例子:
const List<String> images = [
'https://cataas.com/cat?hash=1',
'https://cataas.com/cat?hash=2',
'https://cataas.com/cat?hash=3',
'https://cataas.com/cat?hash=4',
'https://cataas.com/cat?hash=5',
'https://cataas.com/cat?hash=6',
'https://cataas.com/cat?hash=7',
'https://cataas.com/cat?hash=8',
];
// Scaffold child
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView(
children: [
// Header
Placeholder(
fallbackHeight: 300,
),
Category(),
SizedBox(height: 16),
Category(),
],
);
}
}
class Category extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('Build category');
return Column(
children: [
Padding(
padding: EdgeInsets.all(32),
child: Text('CATEGORY TITLE'),
),
...images.map((image) => CategoryItem(image)),
],
);
}
}
class CategoryItem extends StatelessWidget {
final String imageUrl;
CategoryItem(this.imageUrl);
@override
Widget build(BuildContext context) {
print('Build image: $imageUrl');
return FadeInImage.memoryNetwork(
fit: BoxFit.cover,
placeholder: kTransparentImage,
image: imageUrl,
);
}
}
您需要使用 ListView.builder
,因为它会延迟渲染其子项。此外,您还需要使用一个列表。
问题是在加载之前您不知道图像的大小,因此所有高度为 0 的图像都会立即构建。但是,如果您为它们设置固定高度,它将按预期工作。
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
final children = [
// Header
Placeholder(
fallbackHeight: 300,
),
Padding(
padding: EdgeInsets.all(32),
child: Text('CATEGORY TITLE'),
),
...images.map((image) => CategoryItem(image)),
SizedBox(height: 16),
Padding(
padding: EdgeInsets.all(32),
child: Text('CATEGORY TITLE'),
),
...images.map((image) => CategoryItem(image)),
];
return Scaffold(
body: ListView.builder(
itemCount: children.length,
itemBuilder: (context, i) => children[i],
)
);
}
}