【问题标题】:Preload network images using PageView使用 PageView 预加载网络图像
【发布时间】:2018-06-03 03:41:43
【问题描述】:

我目前正在开发一个阅读器并使用PageView 来滑动图像页面。如何使下一页预加载,以便用户可以滑动到下一页而无需等待页面加载?我不想先下载所有页面,因为它会加载服务器并冻结我的应用程序。当用户浏览当前页面时,我只想下载接下来的一两个页面。

这是我的代码的摘录。

PageController _controller;
ZoomableImage nextPage;

Widget _loadImage(int index) {
  ImageProvider image = new CachedNetworkImageProvider("https://example.com/${bookId}/${index+1}.jpg}");
  ZoomableImage zoomed = new ZoomableImage(
              image, 
              placeholder: new Center(
                child: CupertinoActivityIndicator(),
              ),
            );
    return zoomed;
  }

@override
Widget build(BuildContext context) {
  return new Scaffold(
    body: new Container(
      child: PageView.builder(
        physics: new AlwaysScrollableScrollPhysics(),
        controller: _controller,
        itemCount: book.numPages,
        itemBuilder: (BuildContext context, int index) {
          return index == 0 || index == 1 ? _loadImage(index) : nextPage;
        },
        onPageChanged: (int index) {
          nextPage = _loadImage(index+1);
        },
      ),
    ),
  );
}

谢谢!

【问题讨论】:

    标签: dart flutter


    【解决方案1】:

    正如人们之前提到的,cached_network_image 库是一个解决方案,但并不适合我的情况。我的项目中有一个完整的页面PageView(适合宽度和高度),当我尝试以前的代码时,我的PageView 将首先显示一个空白页面,然后显示图像。

    我开始阅读PageView 源代码,终于找到了适合我个人要求的方法。基本思路是改PageView源码的cacheExtent

    这是关于 cacheExtent 工作原理的描述:

    视口在可见区域之前和之后都有一个区域,用于缓存用户滚动时即将变为可见的项目。

    位于此缓存区域中的项目即使在屏幕上(还)不可见也会被布局。 cacheExtent 描述了缓存区域在视口前沿之前和后沿之后延伸了多少像素。

    直接更改flutter的源代码是个坏主意,所以我创建a new PrelodPageView widget并在需要预加载功能时在特定位置使用它。

    编辑:

    我再添加一个参数preloadPagesCount 用于自动预加载多个页面。

    https://pub.dartlang.org/packages/preload_page_view

    【讨论】:

    • 这是有效的,但我更换了我的笔记本电脑,现在我遇到了错误。
    【解决方案2】:

    简单!只需设置allowImplicitScrolling: true, // in PageView.builder

    【讨论】:

    • 我无法相信回答这个问题有多简短、简单和直接,像魅力一样解决了我的类似情况,谢谢
    【解决方案3】:

    我最终使用 cached_network_image 包中的 FutureBuilderCachedNetworkImageProvider 来预取所有图像。这是我的解决方案:

    PageController _controller;
    ZoomableImage currPage, nextPage;
    
    Future<List<CachedNetworkImageProvider>> _loadAllImages(Book book) async {
      List<CachedNetworkImageProvider> cachedImages = [];
      for(int i=0;i<book.numPages;i++) {
        var configuration = createLocalImageConfiguration(context);
        cachedImages.add(new CachedNetworkImageProvider("https://example.com/${bookId}/${index+1}.jpg}")..resolve(configuration));
      }
      return cachedImages;
    }
    
    FutureBuilder<List<CachedNetworkImageProvider>> _futurePages(Book book) {
      return new FutureBuilder(
        future: _loadAllImages(book),
        builder: (BuildContext context, AsyncSnapshot snapshot){
          if(snapshot.hasData) {
            return new Container(
              child: PageView.builder(
                physics: new AlwaysScrollableScrollPhysics(),
                controller: _controller,
                itemCount: snapshot.data.length,
                itemBuilder: (BuildContext context, int index) {
                  ImageProvider image = snapshot.data[index];
                  return new ZoomableImage(
                    image, 
                    placeholder: new Center(
                      child: CupertinoActivityIndicator(),
                    ),
                  );
                },
                onPageChanged: (int index) {},
              ),
            );
          } else if(!snapshot.hasData) return new Center(child: CupertinoActivityIndicator());
        },
      );
    }
    
    @override
    Widget build(BuildContext context) {
      return new Scaffold(
        body: _futurePages(widget.book),
      );
    }
    

    【讨论】:

    • 谁能告诉我CachedNetworkImageProvider allowImplicitScrolling: true, // in PageView.builder之间的区别,
    • 不看细节,这个解决方案已经 2.5 年了,所以也许 allowImplicitScrolling 是后来添加的。
    猜你喜欢
    • 2018-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-25
    • 1970-01-01
    • 2011-04-08
    • 2019-11-01
    相关资源
    最近更新 更多