【问题标题】:Load image only if it's inside viewport仅当图像在视口内时才加载图像
【发布时间】:2019-12-05 13:24:30
【问题描述】:

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

【问题讨论】:

    标签: flutter dart lazy-loading


    【解决方案1】:

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

    【讨论】:

    • 我想将类别用作小部件的另一个原因是,在我的应用程序中,它使用 StreamBuilder 来获取图像 url 列表,因此无法使用此解决方案。我会修正我的例子
    • @Anton 我不明白这会如何阻止您使用单个列表。在这种情况下,您可以将多个流合并为一个,并在 StreamBuilder 中只使用一次。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-16
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 2018-06-21
    相关资源
    最近更新 更多