是否可以使用“合成布局”创建具有动态宽度但固定高度的单元格

时间:2020-05-23 22:20:54

标签: ios swift dynamic uicollectionview uicollectionviewcompositionallayout

TLDR; 根据部分,我需要调整单元格的大小:

  1. 固定宽度但动态高度(例如,全屏宽度和自动高度取决于内容)
  2. 动态宽度,但高度固定(第一个单元格的宽度可能为120pt,第二个单元格的宽度可能为155pt等)

这是我们需要消除可能存在的任何歧义的象形图。 enter image description here

我只是在寻找:“是的,您可以通过合成布局来实现这一点,这是...”。或“否,您不能使用合成实现此功能,必须使用流布局或其他自定义布局。”

附加要求:

  1. 建议的解决方案不应建议在流布局中使用collectionView(_:layout:sizeForItemAt:),因为这是我们要避免的事情。如果是答案,那么您可以简单地说-“不,这不能通过合成布局实现。”
  2. 提出的解决方案应让集合视图确定如何根据其固有内容大小适当放置单元。这类似于UITableViewAutomaticDimension 使用tableview的动态自调整功能

背景信息:

  • 很清楚如何使用合成布局实现全宽但动态高度的单元格。参见this exchange
  • herehere记录了具有自动内容大小的流布局的已知限制。那是写O'Reilly books之一的人。基本上,他说即使Apple声称确实没有自动调整流程布局的大小。因此,试图通过“合成布局”解决这一问题。

1 个答案:

答案 0 :(得分:3)

您可以使用UICollectionViewCompositionalLayout构建“第2节”布局。方法如下:

let layoutSize = NSCollectionLayoutSize(
    widthDimension: .estimated(100),
    heightDimension: .absolute(32)
)

let group = NSCollectionLayoutGroup.horizontal(
    layoutSize: .init(
        widthDimension: .fractionalWidth(1.0),
        heightDimension: layoutSize.heightDimension
    ),
    subitems: [.init(layoutSize: layoutSize)]
)
group.interItemSpacing = .fixed(8)

let section = NSCollectionLayoutSection(group: group)
section.contentInsets = .init(top: 0, leading: 16, bottom: 0, trailing: 16)
section.interGroupSpacing = 8

return .init(section: section)

重要的一点是,该组使用.fractionalWidth(1.0)占用了可用宽度,但是子项具有估计的宽度。只需通过覆盖sizeThatFits(_:)preferredLayoutAttributesFitting(_:)或使用“自动布局”来确保您的收藏夹视图单元格可以自动调整大小即可。结果将是一个如下所示的布局:

enter image description here

要在同一UICollectionViewCompositionalLayout中使用“ section 1”和“ section 2”,只需使用init(sectionProvider:)创建布局,在其中为当前部分标识符返回相应的NSCollectionLayoutSection

func createCollectionViewLayout() -> UICollectionViewCompositionalLayout {
    .init(sectionProvider: { [weak self] sectionIndex, _ in
        guard let sectionIdentifier = self?.dataSource.snapshot().sectionIdentifiers[sectionIndex] else { return nil }
        switch sectionIdentifier {
        case .section1: return self?.createSection1()
        case .section2: return self?.createSection2()
        }
    })
}

值得注意的是,如果您的视图控制器在iOS 13+上使用默认的pageSheet样式呈现,则此布局可能会出现一些奇怪的行为。我在这里有一个related question(使用略有不同的布局)。