Skip to content
This repository was archived by the owner on Nov 4, 2022. It is now read-only.

Commit e71eda8

Browse files
V1.7.0 (#150)
- Add support for setting scrollPosition through binding - Improve function builders, support for unlimited number of static views, support for arrays - Improve default self-sizing settings - Support for automatic keyboard avoidance
1 parent 91c0984 commit e71eda8

31 files changed

+613
-513
lines changed

.github/FUNDING.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@
99
#liberapay: # Replace with a single Liberapay username
1010
#issuehunt: # Replace with a single IssueHunt username
1111
#otechie: # Replace with a single Otechie username
12+
github: apptekstudios
1213
custom: ['https://www.buymeacoffee.com/tobeasbrennan'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

.swiftformat

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
--fractiongrouping disabled
2121
--ifdef outdent
2222
--importgrouping testable-top
23-
--stripunusedargs closure-only
2423
--wraparguments before-first
2524
--wrapcollections after-first
25+
26+
--disable unusedArguments

ASCollectionView-SwiftUI.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Pod::Spec.new do |s|
33
s.name = 'ASCollectionView-SwiftUI'
4-
s.version = '1.6.3'
4+
s.version = '1.7.0'
55
s.summary = 'A SwiftUI collection view with support for custom layouts, preloading, and more. '
66

77
s.description = <<-DESC

Demo/ASCollectionViewDemo/Screens/AppStore/AppStoreScreen.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,9 @@ struct AppStoreScreen: View
6161
{
6262
ASCollectionView(sections: self.sections)
6363
.layout(self.layout)
64+
.contentInsets(.init(top: 10, left: 0, bottom: 10, right: 0))
6465
.shouldAttemptToMaintainScrollPositionOnOrientationChange(maintainPosition: false)
65-
.navigationBarTitle("Apps", displayMode: .large)
66+
.navigationBarTitle("Apps", displayMode: .inline)
6667
.edgesIgnoringSafeArea(.all)
6768
}
6869

@@ -138,6 +139,8 @@ extension AppStoreScreen
138139
section.interGroupSpacing = 20
139140
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 20)
140141
section.orthogonalScrollingBehavior = .groupPaging
142+
section.visibleItemsInvalidationHandler = { _, _, _ in } // If this isn't defined, there is a bug in UICVCompositional Layout that will fail to update sizes of cells
143+
141144
return section
142145
}
143146
case 1:
@@ -175,6 +178,8 @@ extension AppStoreScreen
175178
section.boundarySupplementaryItems = [header]
176179
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 20)
177180
section.orthogonalScrollingBehavior = .groupPaging
181+
section.visibleItemsInvalidationHandler = { _, _, _ in } // If this isn't defined, there is a bug in UICVCompositional Layout that will fail to update sizes of cells
182+
178183
return section
179184
}
180185
default:
@@ -212,6 +217,8 @@ extension AppStoreScreen
212217
section.boundarySupplementaryItems = [header]
213218
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 20)
214219
section.orthogonalScrollingBehavior = .groupPaging
220+
section.visibleItemsInvalidationHandler = { _, _, _ in } // If this isn't defined, there is a bug in UICVCompositional Layout that will fail to update sizes of cells
221+
215222
return section
216223
}
217224
}

Demo/ASCollectionViewDemo/Screens/InstaFeed/PostView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ struct PostView: View
100100
)
101101
buttonBar
102102
textContent
103-
Spacer()
103+
Spacer().layoutPriority(2)
104104
}
105105
.padding([.top, .bottom])
106106
}

Demo/BuildTools/Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Sources/ASCollectionView/ASCollectionView+Modifiers.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,12 @@ public extension ASCollectionView
108108
return this
109109
}
110110

111-
/// Set an initial scroll position for the ASCollectionView
112-
func initialScrollPosition(_ position: ASCollectionViewScrollPosition?) -> Self
111+
/// Set a binding that will scroll the ASCollectionView when set. It will always return nil once the scroll is applied (use onScroll to read scroll position)
112+
func scrollPositionSetter(_ binding: Binding<ASCollectionViewScrollPosition?>) -> Self
113113
{
114114
var this = self
115-
this.initialScrollPosition = position
115+
_ = binding.wrappedValue // Touch the binding so that SwiftUI will notify us of future updates
116+
this.scrollPositionSetter = binding
116117
return this
117118
}
118119

Sources/ASCollectionView/ASTableView+Modifiers.swift

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,22 @@ public extension ASTableViewSection
8181
{
8282
func sectionHeaderInsetGrouped<Content: View>(content: () -> Content?) -> Self
8383
{
84-
var section = self
85-
let insetGroupedContent =
86-
content()
87-
.font(.headline)
88-
.frame(maxWidth: .infinity, alignment: .leading)
89-
.padding(EdgeInsets(top: 12, leading: 0, bottom: 6, trailing: 0))
84+
if let content = content()
85+
{
86+
var section = self
87+
let insetGroupedContent =
88+
content
89+
.font(.headline)
90+
.frame(maxWidth: .infinity, alignment: .leading)
91+
.padding(EdgeInsets(top: 12, leading: 0, bottom: 6, trailing: 0))
9092

91-
section.setHeaderView(insetGroupedContent)
92-
return section
93+
section.setHeaderView(insetGroupedContent)
94+
return section
95+
}
96+
else
97+
{
98+
return self
99+
}
93100
}
94101
}
95102

Sources/ASCollectionView/Cells/ASCollectionViewCell.swift

Lines changed: 38 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -7,117 +7,103 @@ import UIKit
77
@available(iOS 13.0, *)
88
class ASCollectionViewCell: UICollectionViewCell, ASDataSourceConfigurableCell
99
{
10-
var indexPath: IndexPath?
1110
var itemID: ASCollectionViewItemUniqueID?
1211
var hostingController: ASHostingControllerProtocol?
1312
{
14-
didSet
15-
{
16-
hostingController?.invalidateCellLayoutCallback = invalidateLayoutCallback
17-
hostingController?.collectionViewScrollToCellCallback = scrollToCellCallback
18-
}
13+
get { _hostingController }
14+
set { _hostingController = newValue; attachView() }
1915
}
2016

21-
weak var collectionView: UICollectionView?
17+
private var _hostingController: ASHostingControllerProtocol?
2218

19+
weak var collectionViewController: AS_CollectionViewController?
2320
var selfSizingConfig: ASSelfSizingConfig = .init(selfSizeHorizontally: true, selfSizeVertically: true)
2421

25-
var invalidateLayoutCallback: ((_ animated: Bool) -> Void)?
26-
var scrollToCellCallback: ((UICollectionView.ScrollPosition) -> Void)?
27-
28-
func willAppear(in vc: UIViewController)
22+
private var hasAppeared: Bool = false // Needed due to the `self-sizing` cell used by UICV
23+
func willAppear()
2924
{
30-
if hostingController?.viewController.parent != vc
31-
{
32-
hostingController?.viewController.removeFromParent()
33-
hostingController.map { vc.addChild($0.viewController) }
34-
attachView()
35-
hostingController?.viewController.didMove(toParent: vc)
36-
}
25+
hasAppeared = true
26+
attachView()
3727
}
3828

3929
func didDisappear()
4030
{
41-
hostingController?.viewController.removeFromParent()
31+
hasAppeared = false
32+
detachViews()
4233
}
4334

4435
private func attachView()
4536
{
37+
guard hasAppeared else { return }
4638
guard let hcView = hostingController?.viewController.view else
4739
{
4840
detachViews()
4941
return
5042
}
5143
if hcView.superview != contentView
5244
{
45+
hostingController.map { collectionViewController?.addChild($0.viewController) }
5346
contentView.subviews.forEach { $0.removeFromSuperview() }
5447
contentView.addSubview(hcView)
55-
setNeedsLayout()
48+
hcView.frame = contentView.bounds
49+
hostingController?.viewController.didMove(toParent: collectionViewController)
5650
}
5751
}
5852

5953
private func detachViews()
6054
{
55+
hostingController?.viewController.willMove(toParent: nil)
6156
contentView.subviews.forEach { $0.removeFromSuperview() }
57+
hostingController?.viewController.removeFromParent()
6258
}
6359

64-
var shouldSkipNextRefresh: Bool = true
65-
6660
override func prepareForReuse()
6761
{
68-
indexPath = nil
6962
itemID = nil
7063
isSelected = false
71-
hostingController = nil
72-
shouldSkipNextRefresh = true
64+
alpha = 1.0
65+
_hostingController = nil
7366
}
7467

7568
override func layoutSubviews()
7669
{
7770
super.layoutSubviews()
7871

79-
attachView()
80-
8172
if hostingController?.viewController.view.frame != contentView.bounds
8273
{
83-
UIView.performWithoutAnimation {
84-
hostingController?.viewController.view.frame = contentView.bounds
85-
hostingController?.viewController.view.setNeedsLayout()
86-
hostingController?.viewController.view.layoutIfNeeded()
87-
}
74+
hostingController?.viewController.view.frame = contentView.bounds
75+
hostingController?.viewController.view.setNeedsLayout()
8876
}
77+
hostingController?.viewController.view.layoutIfNeeded()
8978
}
9079

91-
override func systemLayoutSizeFitting(_ targetSize: CGSize) -> CGSize
80+
override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize
9281
{
93-
guard let hc = hostingController else
82+
guard let hostingController = hostingController else { return CGSize(width: 1, height: 1) }
83+
84+
let selfSizeHorizontal = selfSizingConfig.selfSizeHorizontally ?? (horizontalFittingPriority != .required)
85+
let selfSizeVertical = selfSizingConfig.selfSizeVertically ?? (verticalFittingPriority != .required)
86+
87+
guard selfSizeVertical || selfSizeHorizontal else
9488
{
95-
return CGSize(width: 1, height: 1)
96-
} // Can't return .zero as UICollectionViewLayout will crash
89+
return targetSize
90+
}
9791

98-
let size = hc.sizeThatFits(
92+
// We need to calculate a size for self-sizing. Layout the view to get swiftUI to update its state
93+
hostingController.viewController.view.setNeedsLayout()
94+
hostingController.viewController.view.layoutIfNeeded()
95+
let size = hostingController.sizeThatFits(
9996
in: targetSize,
10097
maxSize: maxSizeForSelfSizing,
101-
selfSizeHorizontal: selfSizingConfig.selfSizeHorizontally,
102-
selfSizeVertical: selfSizingConfig.selfSizeVertically)
98+
selfSizeHorizontal: selfSizeHorizontal,
99+
selfSizeVertical: selfSizeVertical)
103100
return size
104101
}
105102

106-
override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize
107-
{
108-
systemLayoutSizeFitting(targetSize)
109-
}
110-
111-
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes
112-
{
113-
layoutAttributes.size = systemLayoutSizeFitting(layoutAttributes.size)
114-
return layoutAttributes
115-
}
116-
117103
var maxSizeForSelfSizing: ASOptionalSize
118104
{
119105
ASOptionalSize(
120-
width: selfSizingConfig.canExceedCollectionWidth ? nil : collectionView.map { $0.contentSize.width - 0.001 },
121-
height: selfSizingConfig.canExceedCollectionHeight ? nil : collectionView.map { $0.contentSize.height - 0.001 })
106+
width: selfSizingConfig.canExceedCollectionWidth ? nil : collectionViewController.map { $0.collectionView.contentSize.width - 0.001 },
107+
height: selfSizingConfig.canExceedCollectionHeight ? nil : collectionViewController.map { $0.collectionView.contentSize.height - 0.001 })
122108
}
123109
}

Sources/ASCollectionView/Cells/ASCollectionViewDecoration.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,8 @@ class ASCollectionViewDecoration<Content: Decoration>: ASCollectionViewSupplemen
1616
override init(frame: CGRect)
1717
{
1818
super.init(frame: frame)
19-
let view = Content()
20-
hostingController = ASHostingController(view)
21-
willAppear(in: nil)
19+
hostingController = ASHostingController(Content())
20+
willAppear()
2221
}
2322

2423
required init?(coder: NSCoder)

0 commit comments

Comments
 (0)