UIImageView图片无法适配CollectionViewCell,滚动后异常变大
问题:CollectionViewCell内UIImageView设置scaleToFill后显示异常,滚动后恢复正常
我从API获取高清图片,需要缩放适配到CollectionViewCell中。初始化UIImageView时设置了contentMode = .scaleToFill,但图片初始仍保持原始比例,滚动CollectionView后才会填充整个Cell尺寸。
相关代码
Cell代码
final class SnapCarouselCellImpl: UICollectionViewCell, SnapCarouselCell{ var imageView: UIImageView = { let imageView = UIImageView() imageView.contentMode = .scaleToFill imageView.translatesAutoresizingMaskIntoConstraints = false return imageView }() override init(frame: CGRect) { super.init(frame: frame) addSubview(imageView) imageView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true imageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true imageView.leftAnchor.constraint(equalTo: contentView.leftAnchor).isActive = true imageView.rightAnchor.constraint(equalTo: contentView.rightAnchor).isActive = true } }
VC代码
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SnapCarouselCell", for: indexPath) as! SnapCarouselCellImpl let item = items[indexPath.row % items.count] cell.imageView.image = UIImage(data: item.poster) return cell } private func setUpCollectionView() -> UICollectionView{ let collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: flowLayout) collectionView.showsHorizontalScrollIndicator = false collectionView.frame = CGRect(x: 0, y: 100, width: view.frame.size.width, height: cellHeight * 1.2) collectionView.decelerationRate = .init(rawValue: 20) collectionView.register(SnapCarouselCellImpl.self, forCellWithReuseIdentifier: "SnapCarouselCell") return collectionView }
FlowLayout代码
override func prepare() { scrollDirection = .horizontal minimumLineSpacing = 20 itemSize = CGSize(width: cellWidth, height: cellHeight) let sideMargin = (collectionView!.bounds.width - cellWidth) / 2.0 sectionInset = UIEdgeInsets(top: 0.0, left: sideMargin, bottom: 0.0, right: sideMargin) }
效果截图
初始效果:
滚动后效果:
解决方案
开启UIImageView的裁剪功能
默认clipsToBounds为false,即使设置了scaleToFill,图片超出Cell的部分不会被裁剪,视觉上看起来没填充整个Cell。在UIImageView初始化时添加:imageView.clipsToBounds = true修正FlowLayout的布局时机
prepare()方法中使用collectionView!.bounds.width可能在CollectionView还未完成布局时拿到的是初始值,导致itemSize和内边距计算错误。可以在layoutAttributesForElements(in:)中动态更新内边距:override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { let attrs = super.layoutAttributesForElements(in: rect) guard let cv = collectionView else { return attrs } let sideMargin = (cv.bounds.width - cellWidth) / 2.0 sectionInset = UIEdgeInsets(top: 0, left: sideMargin, bottom: 0, right: sideMargin) return attrs }Cell复用时显式重置属性
由于Cell复用机制,可能某些场景下contentMode或clipsToBounds被意外修改,在cellForItemAt中重新设置一次:func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SnapCarouselCell", for: indexPath) as! SnapCarouselCellImpl let item = items[indexPath.row % items.count] cell.imageView.contentMode = .scaleToFill cell.imageView.clipsToBounds = true cell.imageView.image = UIImage(data: item.poster) return cell }确认图片加载完整性
确保item.poster是完整的图片数据,如果是异步加载场景(比如后续改用网络库),要保证图片加载完成后刷新对应Cell,避免因图片未完全加载导致的显示异常。
内容的提问来源于stack exchange,提问作者Igor Ševtšenko
相关产品推荐
相关产品推荐

