如何垂直居中UICollectionView内容

问题描述 投票:0回答:8

我正在尝试动态居中 UICollectionView 的内容,但是现有的解决方案都没有考虑到每行可能有多个单元格这一事实。

我已经在 UINavigationBar 中尝试过这个 center 自定义标题? 以及这里的两种解决方案:UICollectionView 垂直居中,但无济于事。

我很惊讶iOS默认情况下没有提供这样做的方法,更重要的是不可能获取当前显示的行数(这也可以解决我的问题)。另外,我无法获得内容的大小(而不仅仅是框架的大小),这也可以帮助我实现所需的效果。

我有这个:

 --------
|X X X X |
|X X X X |
|        |
|        |
 --------

但我想要这个:

 --------
|        |
|X X X X |
|X X X X |
|        |
 --------

任何帮助将不胜感激,

非常感谢。

ios swift swift2
8个回答
32
投票

不确定为什么无法获取内容的大小 -

UICollectionView
UIScrollView
子类,因此可以访问
contentSize
属性。如果您只需要将单元格居中,以防它们在不滚动的情况下全部可见,您可以简单地执行以下操作:

collectionView.contentInset.top = max((collectionView.frame.height - collectionView.contentSize.height) / 2, 0)

当单元格数量增加,导致并非所有单元格都在屏幕上可见并且您开始使用垂直滚动时,这也将起作用 - 顶部插图将设置为

0


4
投票

现在我明白你的问题了。根据屏幕尺寸,您需要另一个插图才能使其看起来居中。然后你必须手动计算它,但这应该不难。您知道可用空间、项目数量和单元格大小。只需计算从顶部插入的截面即可。


1
投票

如果将 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)

0
投票

这是一个旧线程,但我认为缺乏最明显的解决方案。

我会简单地将 UICollectionView 放入完整视图容器中,并将集合视图与自动布局居中对齐。

UICollectionView 应采用最佳大小以适合单元格,然后保持居中。


0
投票

使用 UICollectionViewCompositionalLayout 时,您可以将组内的项目垂直居中。

  1. 在下面的代码片段中,集合视图中有一个部分,即水平滚动。
  2. 在此部分中,可能有多个组,每个组中只有一个项目(以启用
    orthogonalScrollingBehavior = .groupPaging
    )。
  3. 项目的大小是根据自动布局约束进行估计和计算的。
  4. 列表项使用以下方式垂直居中:
 item.edgeSpacing = .init(
     leading: .none,
     top: .flexible(0),
     trailing: .none,
     bottom: .flexible(0)
 )

layout example

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
    }
}

-1
投票

UICollectionView
有一个
visibleCells
属性,返回一个数组。 您可以使用
count
上的
NSArray
属性来获取可见单元格的数量。

您应该能够在委托实现中实现


- collectionView:layout:insetForSectionAtIndex:
,将顶部插图设置为您要拍摄的居中位置。

如果需要,您还可以继承

UICollectionViewFlowLayout
并实现自己的布局逻辑。


-1
投票

如果您有 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 减法并保留其余部分...


-1
投票

将其添加到 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)
© www.soinside.com 2019 - 2024. All rights reserved.