仅当图像位于视口内时才加载图像

Ant*_*ton 1 lazy-loading dart flutter

我有一个带有 ListView 作为子项的脚手架,可以滚动。其顶部有一个标题容器和一个包含图像列表的列。

我只想在这些图像出现在视口中时加载这些图像,但所有图像都开始同时加载。

当我将此图像添加到 ListView 的子项时,不会发生这种情况,但我想将它们放入单独的小部件以保持代码干净。是否可以?

这是一个简化的示例:

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,
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

Igo*_*din 5

您需要使用ListView.builder,因为它会延迟渲染其子项。您还需要使用一个列表。

问题是您在加载之前不知道图像的大小,因此所有高度为 0 的图像都会立即构建。但如果你为它们设置固定高度,它就会按预期工作。

1

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],
      )
    );
  }
}
Run Code Online (Sandbox Code Playgroud)