如何在UICollectionView中实现ImageView的AspectFit、底部对齐及圆角?
实现iOS文件管理器风格的UICollectionView图片排列(ImageView相关代码)
刚好我之前做过类似的需求,给你整理一下完美匹配你三个要求的ImageView实现方案:
1. 配置AspectFit模式
系统UIImageView本身就支持scaleAspectFit模式,直接设置就能让图片保持原始宽高比,完整显示且不超出ImageView边界:
let imageView = UIImageView() imageView.contentMode = .scaleAspectFit // 后续圆角需要用到这个属性,确保图片不会超出圆角范围 imageView.clipsToBounds = true
2. 实现图片底部对齐
默认的scaleAspectFit是让图片居中显示的,要改成底部对齐,有两种靠谱的实现方式:
方式一:自定义ImageView(推荐,复用更稳定)
写个自定义ImageView子类,重写layoutSubviews手动调整图片位置,这样不管ImageView尺寸怎么变,图片都会保持AspectFit且贴底:
class BottomAlignedImageView: UIImageView { override func layoutSubviews() { super.layoutSubviews() guard let image = self.image else { return } // 计算AspectFit模式下图片的实际显示尺寸 let imageAspectRatio = image.size.width / image.size.height let viewAspectRatio = bounds.width / bounds.height var scaledImageSize: CGSize if imageAspectRatio > viewAspectRatio { scaledImageSize = CGSize(width: bounds.width, height: bounds.width / imageAspectRatio) } else { scaledImageSize = CGSize(width: bounds.height * imageAspectRatio, height: bounds.height) } // 把图片框的Y轴原点移到ImageView底部,实现对齐 var imageFrame = CGRect( x: (bounds.width - scaledImageSize.width) / 2, y: bounds.height - scaledImageSize.height, width: scaledImageSize.width, height: scaledImageSize.height ) // 调整内容显示区域 self.layer.contentsRect = AVMakeRect(aspectRatio: image.size, insideRect: imageFrame) } }
用的时候直接创建这个自定义ImageView的实例就行,不用额外做其他配置。
方式二:通过Cell约束实现(快速上手)
如果不想自定义类,也可以在UICollectionViewCell里给ImageView加约束:
- 给ImageView加底部约束(和cell的容器视图底部对齐)
- 加水平居中约束
- 顶部约束设为大于等于容器顶部(允许顶部留空,图片自然就靠底了)
- 别忘了给ImageView设置
contentMode = .scaleAspectFit和clipsToBounds = true
这种方式适合简单场景,但自定义ImageView在cell复用的时候表现更稳定,不会出现布局偏移的情况。
3. 添加圆角效果
这个很简单,直接给ImageView的layer设置圆角就行,记得要开启clipsToBounds(或者用layer.masksToBounds,效果一样):
// 可以改成和iOS文件管理器一致的8pt圆角 imageView.layer.cornerRadius = 8.0 imageView.clipsToBounds = true // 或者用layer层面的设置,性能差异不大 // imageView.layer.masksToBounds = true
小提示
在UICollectionViewCell的prepareForReuse方法里,记得清空ImageView的图片,避免复用的时候出现旧图片残留:
override func prepareForReuse() { super.prepareForReuse() imageView.image = nil }
内容的提问来源于stack exchange,提问作者PERIPERI
相关产品推荐
相关产品推荐

