如何在UICollectionViewListCell中让自定义附属UIImageView垂直居中?
问题描述
运行以下UIKit应用,该应用使用带组合布局(列表布局)和差异数据源的集合视图,包含一个分区和一行单元格。单元格的前置附属视图是一个UIImageView:
但一旦给UIImageView设置图片,附属视图就不再垂直居中:
对应的代码如下:
import UIKit class ViewController: UIViewController { var collectionView: UICollectionView! var dataSource: UICollectionViewDiffableDataSource<String, String>! override func viewDidLoad() { super.viewDidLoad() configureHierarchy() configureDataSource() } func configureHierarchy() { collectionView = .init(frame: .zero, collectionViewLayout: createLayout()) view.addSubview(collectionView) collectionView.frame = view.bounds } func createLayout() -> UICollectionViewLayout { UICollectionViewCompositionalLayout { section, layoutEnvironment in let config = UICollectionLayoutListConfiguration(appearance: .insetGrouped) return NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment) } } func configureDataSource() { let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, String> { cell, indexPath, itemIdentifier in let iv = UIImageView() iv.backgroundColor = .systemRed // iv.image = .init(systemName: "camera") iv.contentMode = .scaleAspectFit iv.frame.size = .init( width: 40, height: 40 ) cell.accessories = [.customView(configuration: .init( customView: iv, placement: .leading(), reservedLayoutWidth: .actual, maintainsFixedSize: true ))] } dataSource = .init(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: itemIdentifier) } var snapshot = NSDiffableDataSourceSnapshot<String, String>() snapshot.appendSections(["main"]) snapshot.appendItems(["demo"]) dataSource.apply(snapshot, animatingDifferences: false) } }
这看起来像是个bug,但把UIImageView尺寸设为100x100时,即使不设置图片,单元格也不会调整大小,这让我怀疑是自己操作有误。
解决方法
问题出在直接给UIImageView设置frame,UICollectionViewListCell的附属视图布局依赖布局系统识别的视图尺寸,而非手动设置的frame。可以通过以下两种方式修复:
方式一:指定视图固有内容尺寸
替换手动设置frame的代码,直接指定UIImageView的固有内容尺寸:
let iv = UIImageView() iv.backgroundColor = .systemRed iv.image = UIImage(systemName: "camera") iv.contentMode = .scaleAspectFit // 替换frame设置为固有尺寸 iv.intrinsicContentSize = CGSize(width: 40, height: 40)
方式二:添加Auto Layout约束
给UIImageView添加固定宽高约束,让布局系统正确识别其尺寸:
let iv = UIImageView() iv.backgroundColor = .systemRed iv.image = UIImage(systemName: "camera") iv.contentMode = .scaleAspectFit iv.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ iv.widthAnchor.constraint(equalToConstant: 40), iv.heightAnchor.constraint(equalToConstant: 40) ])
无需修改附属视图的配置参数,保持reservedLayoutWidth: .actual和maintainsFixedSize: true即可。调整后,无论是否设置图片,UIImageView都会在附属视图区域内垂直居中,单元格也会根据内容自动适配高度。
内容的提问来源于stack exchange,提问作者Filippo
相关产品推荐
相关产品推荐

