仅在视口内加载图像

时间:2019-12-05 13:24:30

标签: flutter dart lazy-loading

我有一个带有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,
    );
  }
}

1 个答案:

答案 0 :(得分:1)

您需要使用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],
      )
    );
  }
}