You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 11:46:05