UICollectionView滚动卡顿问题:加载本地40张图片时滚动掉帧如何优化?
UICollectionView本地图片滚动卡顿优化方案
核心问题定位
- 重复生成图片数组:你在
numberOfItemsInSection和cellForItemAt中每次都创建新的ThemeManager实例,调用themeBackgroundImages()时都会重新生成包含40个UIImage的数组,大量重复开销完全没必要 - 图片未做降采样:本地原图尺寸远大于cell中imageView的显示尺寸,系统渲染时需要实时对大图做解码、缩放操作,CPU/GPU占用极高,这是滚动卡顿的核心原因
- 重复设置视图属性:每次cell复用都重新设置
cornerRadius,同时未做离屏渲染优化,进一步增加渲染开销 - 之前的异步队列方案无效的原因:卡顿核心不是图片IO耗时,而是图片渲染阶段的主线程开销,就算把加载逻辑放到异步队列,最后渲染依然要在主线程处理,反而会增加线程调度开销。
具体优化代码
1. 页面层缓存降采样后的图片
在ThemesVC中提前加载并处理所有图片,避免滚动时重复计算:
class ThemesVC: UIViewController { // 缓存降采样后的适配尺寸图片,仅初始化一次 private var allThemeImages: [UIImage] = [] override func viewDidLoad() { super.viewDidLoad() // 提前计算目标图片尺寸,和cell大小保持一致 let targetImageSize = CGSize(width: view.frame.width / 2.34, height: view.frame.height * 0.3) let screenScale = UIScreen.main.scale // 一次性加载并降采样所有图片 let rawImages = ThemeManager().themeBackgroundImages() allThemeImages = rawImages.map { image in downsample(image: image, targetSize: targetImageSize, scale: screenScale) } // 其他初始化逻辑... } // 图片降采样方法,将大图缩放到刚好适配控件的尺寸,大幅降低渲染开销 private func downsample(image: UIImage, targetSize: CGSize, scale: CGFloat) -> UIImage { let format = UIGraphicsImageRendererFormat.default() format.scale = scale return UIGraphicsImageRenderer(size: targetSize, format: format).image { _ in image.draw(in: CGRect(origin: .zero, size: targetSize)) } } } // 优化后的数据源方法,直接使用缓存好的图片 extension ThemesVC: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{ func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return allThemeImages.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ThemesCollectionViewCell", for: indexPath) as! ThemesCollectionViewCell cell.themeCellImageView.image = allThemeImages[indexPath.row] return cell } // 其他布局方法保持不变即可... }
2. 优化Cell性能,避免重复配置
将固定属性放到Cell初始化方法中只设置一次,同时开启栅格化缓存渲染结果:
import UIKit class ThemesCollectionViewCell: UICollectionViewCell { @IBOutlet weak var themeCellImageView: UIImageView! override func awakeFromNib() { super.awakeFromNib() // 圆角等固定属性仅设置一次 contentView.layer.cornerRadius = 20 contentView.layer.masksToBounds = true // 开启栅格化,缓存cell渲染结果,滚动时无需重复渲染 layer.shouldRasterize = true layer.rasterizationScale = UIScreen.main.scale } }
3. 优化ThemeManager,缓存原始图片数组
避免每次调用方法都重新生成40张图片的数组:
func themeBackgroundImages() -> [UIImage]{ // 静态缓存,全局仅生成一次图片数组 struct StaticCache { static var cachedImages: [UIImage]? } if let cached = StaticCache.cachedImages { return cached } var images = [UIImage]() images.reserveCapacity(40) // 原有图片赋值逻辑保持不变 images = [UIImage(named: "original-theme")!, UIImage(named: "blue-theme")!, UIImage(named: "purple-theme")!, UIImage(named: "pink-theme")!, UIImage(named: "red-theme")!, FlyTheme().backgroundImage, DreamTheme().backgroundImage, LoverTheme().backgroundImage, NatureTheme().backgroundImage, InspireTheme().backgroundImage, TimeMachineTheme().backgroundImage, NowhereTheme().backgroundImage, DarkThoughtsTheme().backgroundImage, FutureCityTheme().backgroundImage, LostTheme().backgroundImage, FireTheme().backgroundImage, PatternTheme().backgroundImage, HorizonTheme().backgroundImage, SpelTheme().backgroundImage, WonderlandTheme().backgroundImage, BreatheTheme().backgroundImage, PassionTheme().backgroundImage, TimelapseTheme().backgroundImage, FugitiveTheme().backgroundImage, InfiniteWayTheme().backgroundImage, LonelyTheme().backgroundImage, RelationshipTheme().backgroundImage, MoonlightTheme().backgroundImage, DreamlandTheme().backgroundImage, WayOutTheme().backgroundImage, MistyTheme().backgroundImage, UnpredictableTheme().backgroundImage, VolcanoTheme().backgroundImage, DiscoverTheme().backgroundImage, PurpleInspirationTheme().backgroundImage, ForestTheme().backgroundImage, RainbowTheme().backgroundImage, FlowersTheme().backgroundImage, TheMoonTheme().backgroundImage, LuridTheme().backgroundImage] StaticCache.cachedImages = images return images }
内容的提问来源于stack exchange,提问作者ataberkturan
相关产品推荐
相关产品推荐

