Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FabianTerhorst/495493358c6987168c4f79aadec4090e to your computer and use it in GitHub Desktop.
Save FabianTerhorst/495493358c6987168c4f79aadec4090e to your computer and use it in GitHub Desktop.
open class NestedVerticalCellCollectionViewLayout<V: LayoutAdapterCollectionView, C: Collection>: BaseLayout<V>, ConfigurableLayout where C.Iterator.Element == Layout {
private let sectionLayouts: [Section<C>]
public init(sectionLayouts: [Section<C>], alignment: Alignment = .topFill, viewReuseId: String? = nil, config: ((V) -> Void)? = nil) {
self.sectionLayouts = sectionLayouts
super.init(alignment: alignment, flexibility: Flexibility(horizontal: nil, vertical: Flexibility.defaultFlex), viewReuseId: viewReuseId, config: config)
}
private var cachedSectionLayoutMeasurement: [Section<[LayoutMeasurement]>]?
private func measure(within maxSize: CGSize = CGSize.zero) -> [Section<[LayoutMeasurement]>] {
if let cachedSectionLayoutMeasurement = cachedSectionLayoutMeasurement {
return cachedSectionLayoutMeasurement
}
let measurement = self.sectionLayouts.map {
sectionLayout in
return sectionLayout.map { (layout: Layout) -> LayoutMeasurement in
return layout.measurement(within: maxSize)
}
}
cachedSectionLayoutMeasurement = measurement
return measurement
}
open func measurement(within maxSize: CGSize) -> LayoutMeasurement {
let fullHeight = measure(within: maxSize).reduce(0) {
(fullHeight, measuredSection) -> CGFloat in
let headerHeight = measuredSection.header?.size.height ?? 0
let footerHeight = measuredSection.footer?.size.height ?? 0
let fullItemsHeight = measuredSection.items.map({ $0.size.height }).reduce(0, +)
return fullHeight + headerHeight + footerHeight + fullItemsHeight
}
// No intrinsic width, but want to be tall enough for all cell heights
let size = CGSize(width: 0, height: min(fullHeight, maxSize.height))
return LayoutMeasurement(layout: self, size: size, maxSize: maxSize, sublayouts: [])
}
private var sectionArrangements: [Section<[LayoutArrangement]>]? = nil
open func arrangement(within rect: CGRect, measurement: LayoutMeasurement) -> LayoutArrangement {
sectionArrangements = measure().map({ sectionMeasurement in
return sectionMeasurement.map({ (measurement: LayoutMeasurement) -> LayoutArrangement in
let rect = CGRect(x: 0, y: 0, width: rect.width, height: measurement.size.height)
return measurement.arrangement(within: rect)
})
})
let frame = Alignment.fill.position(size: measurement.size, in: rect)
return LayoutArrangement(layout: self, frame: frame, sublayouts: [])
}
open override func configure(view: V) {
super.configure(view: view)
if let sectionArrangements = sectionArrangements {
view.layoutAdapter.reload(arrangement: sectionArrangements)
}
}
open override var needsView: Bool {
return super.needsView || sectionArrangements != nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment