Skip to content
This repository has been archived by the owner on Dec 22, 2023. It is now read-only.

Commit

Permalink
Implement delegate methods for header/footer reference size (#121)
Browse files Browse the repository at this point in the history
* Inital changes for the header in the vertical layout

* Fix footerReferenceSize in calculations for dynamic size

* Implement footer logic

* Implement header/footer changes accross the other layouts

* Set correct zIndex

* Set correct zIndex

* Update VerticalMosaicBlueprintLayout.swift

* Improve zIndex value for headers and footers

* Load correct bundle

* Fix setting min and max for footers
  • Loading branch information
christoff-1992 authored and zenangst committed Aug 5, 2019
1 parent b4be2bc commit c0a4d89
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 71 deletions.
2 changes: 1 addition & 1 deletion Example-OSX/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
var window: NSWindow?

func applicationDidFinishLaunching(_ aNotification: Notification) {
Bundle(path: "/Applications/InjectionIII.app/Contents/Resources/macOSInjection10.bundle")?.load()
Bundle(path: "/Applications/InjectionIII.app/Contents/Resources/macOSInjection.bundle")?.load()

guard let mainScreen = NSScreen.main ?? NSScreen.screens.first else {
fatalError("Expected a display.")
Expand Down
2 changes: 1 addition & 1 deletion Example-iOS/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
#if DEBUG
// Load InjectionIII bundle
// https://itunes.apple.com/us/app/injectioniii/id1380446739?mt=12
Bundle(path: "/Applications/InjectionIII.app/Contents/Resources/iOSInjection10.bundle")?.load()
Bundle(path: "/Applications/InjectionIII.app/Contents/Resources/iOSInjection.bundle")?.load()
#endif

window = UIWindow(frame: UIScreen.main.bounds)
Expand Down
81 changes: 54 additions & 27 deletions Sources/Shared/Core/BlueprintLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -156,37 +156,56 @@
}
}

/// Create supplementary layout attributes.
/// Resolve the size of SupplementaryView at index path.
/// If the collection view's delegate conforms to `(UI/NS)CollectionViewDelegateFlowLayout`, it will
/// query the delegate for the size of the SupplementaryView.
/// It defaults to using the `headerReferenceSize` or `footerReferenceSize` property on collection view flow layout.
///
/// - Parameters:
/// - kind: The supplementary kind, either header or footer.
/// - indexPath: The section index path for the supplementary view.
/// - x: The x coordinate of the header layout attributes.
/// - y: The y coordinate of the header layout attributes.
/// - Returns: A `LayoutAttributes` object of supplementary kind.
func createSupplementaryLayoutAttribute(ofKind kind: BlueprintSupplementaryKind,
indexPath: IndexPath,
atX x: CGFloat = 0,
atY y: CGFloat = 0) -> SupplementaryLayoutAttributes {
let layoutAttribute = SupplementaryLayoutAttributes(
forSupplementaryViewOfKind: kind.collectionViewSupplementaryType,
with: indexPath
)

/// - Parameter indexPath: The index path of the supplementaryView.
/// - Returns: The desired size of the item at the index path.
func resolveSizeForSupplementaryView(ofKind kind: BlueprintSupplementaryKind, at indexPath: IndexPath) -> CGSize {
switch kind {
case .header:
layoutAttribute.size.width = collectionView?.documentRect.width ?? headerReferenceSize.width
layoutAttribute.size.height = headerReferenceSize.height
let height = resolveCollectionView({ collectionView -> CGSize? in
return (collectionView.delegate as? CollectionViewFlowLayoutDelegate)?.collectionView?(collectionView,
layout: self,
referenceSizeForHeaderInSection: indexPath.section)
}, defaultValue: headerReferenceSize).height

let width: CGFloat
if headerReferenceSize.width > 0 {
width = headerReferenceSize.width
} else {
width = collectionView?.documentRect.width ?? headerReferenceSize.width
}

let size = CGSize(
width: width,
height: height
)

return size
case .footer:
layoutAttribute.size.width = collectionView?.documentRect.width ?? footerReferenceSize.width
layoutAttribute.size.height = footerReferenceSize.height
}
let height = resolveCollectionView({ collectionView -> CGSize? in
return (collectionView.delegate as? CollectionViewFlowLayoutDelegate)?.collectionView?(collectionView,
layout: self,
referenceSizeForFooterInSection: indexPath.section)
}, defaultValue: footerReferenceSize).height

let width: CGFloat
if footerReferenceSize.width > 0 {
width = footerReferenceSize.width
} else {
width = collectionView?.documentRect.width ?? footerReferenceSize.width
}

layoutAttribute.zIndex = indexPath.section
layoutAttribute.frame.origin.x = x
layoutAttribute.frame.origin.y = y
let size = CGSize(
width: width,
height: height
)

return layoutAttribute
return size
}
}

/// Resolve collection collection view from layout and return
Expand Down Expand Up @@ -378,9 +397,17 @@
let results = cachedSupplementaryAttributes.filter({
switch scrollDirection {
case .vertical:
return (visibleRect.origin.y >= $0.min && visibleRect.origin.y <= $0.max) || $0.frame.intersects(visibleRect)
if visibleRect.origin.y < 0 {
return $0.frame.intersects(visibleRect)
} else {
return (visibleRect.origin.y >= $0.min && visibleRect.origin.y <= $0.max)
}
case .horizontal:
return (visibleRect.origin.x >= $0.min && visibleRect.origin.x <= $0.max) || $0.frame.intersects(visibleRect)
if visibleRect.origin.x < 0 {
return $0.frame.intersects(visibleRect)
} else {
return (visibleRect.origin.x >= $0.min && visibleRect.origin.x <= $0.max)
}
@unknown default:
fatalError("Case not implemented in current implementation")
}
Expand Down
27 changes: 16 additions & 11 deletions Sources/Shared/Core/HorizontalBlueprintLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -144,15 +144,18 @@
var footerAttribute: SupplementaryLayoutAttributes? = nil
let sectionIndexPath = IndexPath(item: 0, section: section)

if headerReferenceSize.height > 0 {
let layoutAttribute: SupplementaryLayoutAttributes = createSupplementaryLayoutAttribute(
ofKind: .header,
indexPath: sectionIndexPath,
atX: nextX
if resolveSizeForSupplementaryView(ofKind: .header, at: sectionIndexPath).height > 0 {
let layoutAttribute = SupplementaryLayoutAttributes(
forSupplementaryViewOfKind: BlueprintSupplementaryKind.header.collectionViewSupplementaryType,
with: sectionIndexPath
)
layoutAttribute.size = resolveSizeForSupplementaryView(ofKind: .header, at: sectionIndexPath)
layoutAttribute.zIndex = section + numberOfItemsInSection(section)
layoutAttribute.min = nextX
headerAttribute = layoutAttribute
layoutAttribute.frame.origin.x = nextX
layoutAttribute.frame.origin.y = 0
layoutAttributes.append([layoutAttribute])
headerAttribute = layoutAttribute
}

for item in 0..<numberOfItemsInSection(section) {
Expand Down Expand Up @@ -198,13 +201,15 @@
if let previousItem = previousItem, let firstItem = firstItem {
contentSize.width = previousItem.frame.maxX + sectionInset.right

if footerReferenceSize.height > 0 {
let layoutAttribute = createSupplementaryLayoutAttribute(
ofKind: .footer,
indexPath: sectionIndexPath,
atX: nextX
if resolveSizeForSupplementaryView(ofKind: .footer, at: sectionIndexPath).height > 0 {
let layoutAttribute = SupplementaryLayoutAttributes(
forSupplementaryViewOfKind: BlueprintSupplementaryKind.footer.collectionViewSupplementaryType,
with: sectionIndexPath
)
layoutAttribute.size = resolveSizeForSupplementaryView(ofKind: .footer, at: sectionIndexPath)
layoutAttribute.zIndex = section + numberOfItemsInSection(section)
layoutAttribute.min = nextX
layoutAttribute.frame.origin.x = 0
layoutAttribute.frame.origin.y = contentSize.height + footerReferenceSize.height
layoutAttributes[section].append(layoutAttribute)
footerAttribute = layoutAttribute
Expand Down
34 changes: 20 additions & 14 deletions Sources/Shared/Core/VerticalBlueprintLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,16 @@
var footerAttribute: SupplementaryLayoutAttributes? = nil
let sectionIndexPath = IndexPath(item: 0, section: section)

if headerReferenceSize.height > 0 {
let layoutAttribute = createSupplementaryLayoutAttribute(
ofKind: .header,
indexPath: sectionIndexPath,
atY: nextY
if resolveSizeForSupplementaryView(ofKind: .header, at: sectionIndexPath).height > 0 {
let layoutAttribute = SupplementaryLayoutAttributes(
forSupplementaryViewOfKind: BlueprintSupplementaryKind.header.collectionViewSupplementaryType,
with: sectionIndexPath
)
layoutAttribute.zIndex = numberOfSections
layoutAttribute.size = resolveSizeForSupplementaryView(ofKind: .header, at: sectionIndexPath)
layoutAttribute.zIndex = section + numberOfItemsInSection(section)
layoutAttribute.min = nextY
layoutAttribute.frame.size.width = collectionView?.documentRect.width ?? headerReferenceSize.width
layoutAttribute.frame.origin.x = 0
layoutAttribute.frame.origin.y = nextY
layoutAttributes.append([layoutAttribute])
headerAttribute = layoutAttribute
nextY = layoutAttribute.frame.maxY
Expand Down Expand Up @@ -198,16 +199,21 @@
}

if let previousItem = previousItem {
let previousY = nextY
nextY = previousItem.frame.maxY
if footerReferenceSize.height > 0 {
let layoutAttribute = createSupplementaryLayoutAttribute(
ofKind: .footer,
indexPath: sectionIndexPath,
atY: sectionMaxY + sectionInset.bottom
if resolveSizeForSupplementaryView(ofKind: .footer, at: sectionIndexPath).height > 0 {
let layoutAttribute = SupplementaryLayoutAttributes(
forSupplementaryViewOfKind: BlueprintSupplementaryKind.footer.collectionViewSupplementaryType,
with: sectionIndexPath
)
layoutAttribute.size = resolveSizeForSupplementaryView(ofKind: .footer, at: sectionIndexPath)
layoutAttribute.zIndex = section + numberOfItemsInSection(section)
layoutAttribute.min = headerAttribute?.min ?? previousY
layoutAttribute.max = sectionMaxY + sectionInset.bottom
layoutAttribute.frame.origin.x = 0
layoutAttribute.frame.origin.y = sectionMaxY + sectionInset.bottom
layoutAttributes[section].append(layoutAttribute)
layoutAttribute.zIndex = numberOfSections
layoutAttribute.min = headerAttribute?.frame.origin.y ?? nextY
headerAttribute?.max = sectionMaxY + sectionInset.bottom
footerAttribute = layoutAttribute
nextY = layoutAttribute.frame.maxY
} else {
Expand Down
35 changes: 20 additions & 15 deletions Sources/Shared/Mosaic/VerticalMosaicBlueprintLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,18 @@
var footerAttribute: SupplementaryLayoutAttributes? = nil
let sectionIndexPath = IndexPath(item: 0, section: section)

if headerReferenceSize.height > 0 {
let layoutAttribute = createSupplementaryLayoutAttribute(
ofKind: .header,
indexPath: sectionIndexPath,
atY: nextY
if resolveSizeForSupplementaryView(ofKind: .header, at: sectionIndexPath).height > 0 {
let layoutAttribute = SupplementaryLayoutAttributes(
forSupplementaryViewOfKind: BlueprintSupplementaryKind.header.collectionViewSupplementaryType,
with: sectionIndexPath
)
layoutAttribute.size = resolveSizeForSupplementaryView(ofKind: .header, at: sectionIndexPath)
layoutAttribute.zIndex = section + numberOfItemsInSection(section)
layoutAttribute.min = nextY
layoutAttribute.frame.size.width = collectionView?.documentRect.width ?? headerReferenceSize.width
layoutAttribute.frame.origin.x = 0
layoutAttribute.frame.origin.y = nextY
layoutAttributes.append([layoutAttribute])
headerAttribute = layoutAttribute
headerAttribute?.zIndex = numberOfSections
nextY = layoutAttribute.frame.maxY
}

Expand Down Expand Up @@ -134,18 +135,22 @@
}

if let previousAttribute = previousAttribute {
let previousY = nextY
nextY = previousAttribute.frame.maxY
if footerReferenceSize.height > 0 {
let layoutAttribute = createSupplementaryLayoutAttribute(
ofKind: .footer,
indexPath: sectionIndexPath,
atY: nextY + sectionInset.bottom
if resolveSizeForSupplementaryView(ofKind: .footer, at: sectionIndexPath).height > 0 {
let layoutAttribute = SupplementaryLayoutAttributes(
forSupplementaryViewOfKind: BlueprintSupplementaryKind.footer.collectionViewSupplementaryType,
with: sectionIndexPath
)
layoutAttribute.zIndex = numberOfSections
layoutAttribute.min = headerAttribute?.frame.origin.y ?? nextY
layoutAttribute.size = resolveSizeForSupplementaryView(ofKind: .footer, at: sectionIndexPath)
layoutAttribute.zIndex = section + numberOfItemsInSection(section)
layoutAttribute.min = headerAttribute?.min ?? previousY
layoutAttribute.max = sectionMaxY + sectionInset.bottom
layoutAttribute.frame.origin.x = 0
layoutAttribute.frame.origin.y = nextY + sectionInset.bottom
layoutAttributes[section].append(layoutAttribute)
nextY = layoutAttribute.frame.maxY
footerAttribute = layoutAttribute
nextY = layoutAttribute.frame.maxY
} else {
nextY = nextY + sectionInset.bottom
}
Expand Down
4 changes: 2 additions & 2 deletions Tests/Shared/VerticalBlueprintLayoutTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,8 @@ class VerticalBlueprintLayoutTests: XCTestCase {
}

func testVerticalLayoutAttributesWithHeaderAndFooter() {
verticalLayout.headerReferenceSize = CGSize(width: 100, height: 100)
verticalLayout.footerReferenceSize = CGSize(width: 100, height: 100)
verticalLayout.headerReferenceSize = CGSize(width: collectionView.frame.width, height: 100)
verticalLayout.footerReferenceSize = CGSize(width: collectionView.frame.width, height: 100)
verticalLayout.prepare()

let expectedHeaderAndFooterSize: CGSize = .init(width: 200, height: 100)
Expand Down

0 comments on commit c0a4d89

Please sign in to comment.