Flutter垂直PageView本地图片加载缓慢,预缓存方案失效求助
解决垂直PageView本地图片首次切换加载延迟问题
问题分析
你遇到的首次拖动切换页面时图片加载慢的问题,核心原因有三点:
- 直接在
didChangeDependencies中循环调用precacheImage但未等待异步缓存完成,页面提前渲染导致首次切换时缓存未生效 - 每次在
itemBuilder中创建新的AssetImage实例,Flutter图片缓存无法复用,相当于重复加载新资源 PreloadPageView的preloadPagesCount设为全部图片数量,初始化时资源占用过高,反而拖慢预加载效率
解决方案
1. 异步预缓存,等待缓存完成再显示页面
在状态类中添加加载状态,用Future.wait等待所有图片缓存完成后再渲染页面:
bool _isImagesPreCached = false; List<AssetImage> _cachedImages = []; Future<void> _precacheAllImages() async { final List<Future<void>> precacheFutures = []; for (final path in imagesPaths) { final assetImage = AssetImage(path); _cachedImages.add(assetImage); precacheFutures.add(precacheImage(assetImage, context)); } await Future.wait(precacheFutures); if (mounted) { setState(() { _isImagesPreCached = true; }); } } @override void didChangeDependencies() { super.didChangeDependencies(); if (!_isImagesPreCached) { _precacheAllImages(); } }
2. 复用缓存的AssetImage实例
在itemBuilder中直接使用预缓存好的_cachedImages,避免重复创建实例导致缓存失效:
Image( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, image: _cachedImages[index], // 复用缓存实例 fit: BoxFit.fill, gaplessPlayback: true, // 开启无缝切换,避免空白闪烁 )
3. 优化PreloadPageView预加载数量
不要一次性预加载全部页面,设置合理的预加载数量(比如当前页前后各1页):
PreloadPageView.builder( preloadPagesCount: 2, // 改为2,仅预加载相邻页面 // ...其他参数 )
完整修改后的代码
import 'package:flutter/material.dart'; import 'package:preload_page_view/preload_page_view.dart'; class HomePage extends StatefulWidget { const HomePage({super.key}); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { List<String> dataStored = [ 'ali ahmad', 'noman', 'shabaz', 'Ali Akbar', 'salman rafiq', 'shabaz', 'Ali Akbar', 'salman rafiq' ]; int currentIndex = 0; List<String> imagesPaths = [ 'assets/images/darkImg.jpg', 'assets/images/building.jpg', 'assets/images/leaf.jpg', 'assets/images/street.jpg', 'assets/images/road2.jpg', 'assets/images/leaf.jpg', 'assets/images/street.jpg', 'assets/images/road2.jpg', ]; bool _isImagesPreCached = false; List<AssetImage> _cachedImages = []; Future<void> _precacheAllImages() async { final List<Future<void>> precacheFutures = []; for (final path in imagesPaths) { final assetImage = AssetImage(path); _cachedImages.add(assetImage); precacheFutures.add(precacheImage(assetImage, context)); } await Future.wait(precacheFutures); if (mounted) { setState(() { _isImagesPreCached = true; }); } } @override void didChangeDependencies() { super.didChangeDependencies(); if (!_isImagesPreCached) { _precacheAllImages(); } } @override void dispose() { super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('example'), centerTitle: true, ), body: _isImagesPreCached ? PreloadPageView.builder( preloadPagesCount: 2, scrollDirection: Axis.vertical, itemCount: dataStored.length, itemBuilder: (context, index) { return Stack( children: [ Image( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, image: _cachedImages[index], fit: BoxFit.fill, gaplessPlayback: true, ), Container( decoration: BoxDecoration(border: Border.all(color: Colors.black)), child: Center( child: Text( dataStored[index], style: const TextStyle(fontSize: 30.0, color: Colors.white), ), ), ), Positioned( top: MediaQuery.of(context).size.height * 0.63, right: 0, bottom: 0, child: IconButton( onPressed: () { print('clicked'); }, icon: const Icon(Icons.comment, color: Colors.white), ), ), ], ); }, controller: PreloadPageController(initialPage: 1), onPageChanged: (newIndex) async {}, ) : const Center(child: CircularProgressIndicator()), ); } }
额外优化建议
- 对本地图片进行压缩处理,减小文件大小从根源降低加载耗时
- 确保
pubspec.yaml中正确配置了assets路径,避免资源查找耗时
内容的提问来源于stack exchange,提问作者usama haider
相关产品推荐
相关产品推荐

