我正在尝试动态居中 UICollectionView 的内容,但是现有的解决方案都没有考虑到每行可能有多个单元格这一事实。
我已经在 UINavigationBar 中尝试过这个 center 自定义标题? 以及这里的两种解决方案:UICollectionView 垂直居中,但无济于事。
我很惊讶iOS默认情况下没有提供这样做的方法,更重要的是不可能获取当前显示的行数(这也可以解决我的问题)。另外,我无法获得内容的大小(而不仅仅是框架的大小),这也可以帮助我实现所需的效果。
我有这个:
--------
|X X X X |
|X X X X |
| |
| |
--------
但我想要这个:
--------
| |
|X X X X |
|X X X X |
| |
--------
任何帮助将不胜感激,
非常感谢。
不确定为什么无法获取内容的大小 -
UICollectionView
是 UIScrollView
子类,因此可以访问 contentSize
属性。如果您只需要将单元格居中,以防它们在不滚动的情况下全部可见,您可以简单地执行以下操作:
collectionView.contentInset.top = max((collectionView.frame.height - collectionView.contentSize.height) / 2, 0)
当单元格数量增加,导致并非所有单元格都在屏幕上可见并且您开始使用垂直滚动时,这也将起作用 - 顶部插图将设置为
0
。
现在我明白你的问题了。根据屏幕尺寸,您需要另一个插图才能使其看起来居中。然后你必须手动计算它,但这应该不难。您知道可用空间、项目数量和单元格大小。只需计算从顶部插入的截面即可。
如果将 UICollectionView 与组合布局一起使用,则以下解决方案将起作用:
private func makeFullHeightSection() -> NSCollectionLayoutSection {
let group = NSCollectionLayoutGroup.vertical(
layoutSize: .init(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0)),
subitems: [
.init(
layoutSize: .init(
widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(1.0)
)
)
]
)
let section = NSCollectionLayoutSection(group: group)
return section
}
在全屏单元格中,将内容垂直居中(我使用的是 snapkit):
private func installConstraints() {
stackView.snp.makeConstraints { make in
make.directionalHorizontalEdges.equalToSuperview()
make.centerY.equalToSuperview()
}
设置集合视图的 contentInsetAdjustmentBehavior 属性,如下所示:
collectionView.contentInsetAdjustmentBehavior = .never
如果由于某种原因您想在全屏单元格和不全屏单元格之间进行更改,则在更改 contentInsetAdjustmentBehavior 后,重置 contentOffset:
collectionView.contentOffset = CGPoint(x: 0, y: 0)
这是一个旧线程,但我认为缺乏最明显的解决方案。
我会简单地将 UICollectionView 放入完整视图容器中,并将集合视图与自动布局居中对齐。
UICollectionView 应采用最佳大小以适合单元格,然后保持居中。
使用 UICollectionViewCompositionalLayout 时,您可以将组内的项目垂直居中。
orthogonalScrollingBehavior = .groupPaging
)。 item.edgeSpacing = .init(
leading: .none,
top: .flexible(0),
trailing: .none,
bottom: .flexible(0)
)
private func setupCollectionView() {
collectionView.delegate = self
collectionView.dataSource = collectionDataSource
collectionView.collectionViewLayout = UICollectionViewCompositionalLayout { [weak self] _, environment -> NSCollectionLayoutSection? in
guard let self else { return nil }
let groupHeight = environment.container.contentSize.height * 1.0
let groupWidth = environment.container.contentSize.width * 0.8
let interGroupSpacingH = (environment.container.contentSize.width - groupWidth) / 2
let sectionInsetV = (environment.container.contentSize.height - groupHeight) / 2
// Setup Item
let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(300)
)
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = .zero
item.edgeSpacing = .init(
leading: .none,
top: .flexible(0),
trailing: .none,
bottom: .flexible(0)
)
// Setup Group
let groupSize = NSCollectionLayoutSize(
widthDimension: .absolute(groupWidth),
heightDimension: .absolute(groupHeight)
)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
// Setup Section
let section = NSCollectionLayoutSection(group: group)
section.contentInsets = NSDirectionalEdgeInsets(
top: 0,
leading: interGroupSpacingH,
bottom: 0,
trailing: interGroupSpacingH
)
section.interGroupSpacing = interGroupSpacingH
section.orthogonalScrollingBehavior = .groupPaging
section.visibleItemsInvalidationHandler = { [weak self] _, _, _ in
guard let self = self else { return }
let currentIndexPath = collectionView.indexPathForItem(at: CGPoint(
x: collectionView.contentOffset.x + collectionView.frame.size.width / 2,
y: collectionView.frame.size.height / 2
))
currentIndexPathSubject.value = currentIndexPath
}
return section
}
}
UICollectionView
有一个 visibleCells
属性,返回一个数组。 您可以使用 count
上的 NSArray
属性来获取可见单元格的数量。
- collectionView:layout:insetForSectionAtIndex:
,将顶部插图设置为您要拍摄的居中位置。
如果需要,您还可以继承
UICollectionViewFlowLayout
并实现自己的布局逻辑。
如果您有 tabBar,请执行此操作
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
let navBarHeight = self.navigationController?.navigationBar.frame.height
let collectionViewHeight = (self.collectionView?.frame.height)! - navBarHeight!
let itemsHeight = self.collectionView?.contentSize.height
let topInset = ( collectionViewHeight - itemsHeight! ) / 4
return UIEdgeInsetsMake(topInset ,0, 0 , 0)
}
如果不忽略 tabBar 减法并保留其余部分...
将其添加到 viewDidLoad
let viewHeight: CGFloat = view.center.y
let contentHeight: CGFloat = collectionView.contentSize.height
let marginHeight: CGFloat = (viewHeight - contentHeight) / 2.0
self.collectionView.contentInset = UIEdgeInsets(top: marginHeight, left: 0, bottom: 0, right: 0)