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

Commit

Permalink
V1.7.0 (#150)
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
apptekstudios authored Jun 2, 2020
1 parent 91c0984 commit e71eda8
Show file tree
Hide file tree
Showing 31 changed files with 613 additions and 513 deletions.
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@
#liberapay: # Replace with a single Liberapay username
#issuehunt: # Replace with a single IssueHunt username
#otechie: # Replace with a single Otechie username
github: apptekstudios
custom: ['https://www.buymeacoffee.com/tobeasbrennan'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
3 changes: 2 additions & 1 deletion .swiftformat
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
--fractiongrouping disabled
--ifdef outdent
--importgrouping testable-top
--stripunusedargs closure-only
--wraparguments before-first
--wrapcollections after-first

--disable unusedArguments
2 changes: 1 addition & 1 deletion ASCollectionView-SwiftUI.podspec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

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

s.description = <<-DESC
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ struct AppStoreScreen: View
{
ASCollectionView(sections: self.sections)
.layout(self.layout)
.contentInsets(.init(top: 10, left: 0, bottom: 10, right: 0))
.shouldAttemptToMaintainScrollPositionOnOrientationChange(maintainPosition: false)
.navigationBarTitle("Apps", displayMode: .large)
.navigationBarTitle("Apps", displayMode: .inline)
.edgesIgnoringSafeArea(.all)
}

Expand Down Expand Up @@ -138,6 +139,8 @@ extension AppStoreScreen
section.interGroupSpacing = 20
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 20)
section.orthogonalScrollingBehavior = .groupPaging
section.visibleItemsInvalidationHandler = { _, _, _ in } // If this isn't defined, there is a bug in UICVCompositional Layout that will fail to update sizes of cells

return section
}
case 1:
Expand Down Expand Up @@ -175,6 +178,8 @@ extension AppStoreScreen
section.boundarySupplementaryItems = [header]
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 20)
section.orthogonalScrollingBehavior = .groupPaging
section.visibleItemsInvalidationHandler = { _, _, _ in } // If this isn't defined, there is a bug in UICVCompositional Layout that will fail to update sizes of cells

return section
}
default:
Expand Down Expand Up @@ -212,6 +217,8 @@ extension AppStoreScreen
section.boundarySupplementaryItems = [header]
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 20)
section.orthogonalScrollingBehavior = .groupPaging
section.visibleItemsInvalidationHandler = { _, _, _ in } // If this isn't defined, there is a bug in UICVCompositional Layout that will fail to update sizes of cells

return section
}
}
Expand Down
2 changes: 1 addition & 1 deletion Demo/ASCollectionViewDemo/Screens/InstaFeed/PostView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ struct PostView: View
)
buttonBar
textContent
Spacer()
Spacer().layoutPriority(2)
}
.padding([.top, .bottom])
}
Expand Down
4 changes: 2 additions & 2 deletions Demo/BuildTools/Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"repositoryURL": "https://github.com/nicklockwood/SwiftFormat",
"state": {
"branch": null,
"revision": "03989b9a28f98ea5cad5ca2b22024a8b67aca31c",
"version": "0.44.7"
"revision": "51a784467a51699d688b0662ae5ed76af2795e5f",
"version": "0.44.12"
}
}
]
Expand Down
7 changes: 4 additions & 3 deletions Sources/ASCollectionView/ASCollectionView+Modifiers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,12 @@ public extension ASCollectionView
return this
}

/// Set an initial scroll position for the ASCollectionView
func initialScrollPosition(_ position: ASCollectionViewScrollPosition?) -> Self
/// 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)
func scrollPositionSetter(_ binding: Binding<ASCollectionViewScrollPosition?>) -> Self
{
var this = self
this.initialScrollPosition = position
_ = binding.wrappedValue // Touch the binding so that SwiftUI will notify us of future updates
this.scrollPositionSetter = binding
return this
}

Expand Down
23 changes: 15 additions & 8 deletions Sources/ASCollectionView/ASTableView+Modifiers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,22 @@ public extension ASTableViewSection
{
func sectionHeaderInsetGrouped<Content: View>(content: () -> Content?) -> Self
{
var section = self
let insetGroupedContent =
content()
.font(.headline)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(EdgeInsets(top: 12, leading: 0, bottom: 6, trailing: 0))
if let content = content()
{
var section = self
let insetGroupedContent =
content
.font(.headline)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(EdgeInsets(top: 12, leading: 0, bottom: 6, trailing: 0))

section.setHeaderView(insetGroupedContent)
return section
section.setHeaderView(insetGroupedContent)
return section
}
else
{
return self
}
}
}

Expand Down
90 changes: 38 additions & 52 deletions Sources/ASCollectionView/Cells/ASCollectionViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,117 +7,103 @@ import UIKit
@available(iOS 13.0, *)
class ASCollectionViewCell: UICollectionViewCell, ASDataSourceConfigurableCell
{
var indexPath: IndexPath?
var itemID: ASCollectionViewItemUniqueID?
var hostingController: ASHostingControllerProtocol?
{
didSet
{
hostingController?.invalidateCellLayoutCallback = invalidateLayoutCallback
hostingController?.collectionViewScrollToCellCallback = scrollToCellCallback
}
get { _hostingController }
set { _hostingController = newValue; attachView() }
}

weak var collectionView: UICollectionView?
private var _hostingController: ASHostingControllerProtocol?

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

var invalidateLayoutCallback: ((_ animated: Bool) -> Void)?
var scrollToCellCallback: ((UICollectionView.ScrollPosition) -> Void)?

func willAppear(in vc: UIViewController)
private var hasAppeared: Bool = false // Needed due to the `self-sizing` cell used by UICV
func willAppear()
{
if hostingController?.viewController.parent != vc
{
hostingController?.viewController.removeFromParent()
hostingController.map { vc.addChild($0.viewController) }
attachView()
hostingController?.viewController.didMove(toParent: vc)
}
hasAppeared = true
attachView()
}

func didDisappear()
{
hostingController?.viewController.removeFromParent()
hasAppeared = false
detachViews()
}

private func attachView()
{
guard hasAppeared else { return }
guard let hcView = hostingController?.viewController.view else
{
detachViews()
return
}
if hcView.superview != contentView
{
hostingController.map { collectionViewController?.addChild($0.viewController) }
contentView.subviews.forEach { $0.removeFromSuperview() }
contentView.addSubview(hcView)
setNeedsLayout()
hcView.frame = contentView.bounds
hostingController?.viewController.didMove(toParent: collectionViewController)
}
}

private func detachViews()
{
hostingController?.viewController.willMove(toParent: nil)
contentView.subviews.forEach { $0.removeFromSuperview() }
hostingController?.viewController.removeFromParent()
}

var shouldSkipNextRefresh: Bool = true

override func prepareForReuse()
{
indexPath = nil
itemID = nil
isSelected = false
hostingController = nil
shouldSkipNextRefresh = true
alpha = 1.0
_hostingController = nil
}

override func layoutSubviews()
{
super.layoutSubviews()

attachView()

if hostingController?.viewController.view.frame != contentView.bounds
{
UIView.performWithoutAnimation {
hostingController?.viewController.view.frame = contentView.bounds
hostingController?.viewController.view.setNeedsLayout()
hostingController?.viewController.view.layoutIfNeeded()
}
hostingController?.viewController.view.frame = contentView.bounds
hostingController?.viewController.view.setNeedsLayout()
}
hostingController?.viewController.view.layoutIfNeeded()
}

override func systemLayoutSizeFitting(_ targetSize: CGSize) -> CGSize
override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize
{
guard let hc = hostingController else
guard let hostingController = hostingController else { return CGSize(width: 1, height: 1) }

let selfSizeHorizontal = selfSizingConfig.selfSizeHorizontally ?? (horizontalFittingPriority != .required)
let selfSizeVertical = selfSizingConfig.selfSizeVertically ?? (verticalFittingPriority != .required)

guard selfSizeVertical || selfSizeHorizontal else
{
return CGSize(width: 1, height: 1)
} // Can't return .zero as UICollectionViewLayout will crash
return targetSize
}

let size = hc.sizeThatFits(
// We need to calculate a size for self-sizing. Layout the view to get swiftUI to update its state
hostingController.viewController.view.setNeedsLayout()
hostingController.viewController.view.layoutIfNeeded()
let size = hostingController.sizeThatFits(
in: targetSize,
maxSize: maxSizeForSelfSizing,
selfSizeHorizontal: selfSizingConfig.selfSizeHorizontally,
selfSizeVertical: selfSizingConfig.selfSizeVertically)
selfSizeHorizontal: selfSizeHorizontal,
selfSizeVertical: selfSizeVertical)
return size
}

override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize
{
systemLayoutSizeFitting(targetSize)
}

override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes
{
layoutAttributes.size = systemLayoutSizeFitting(layoutAttributes.size)
return layoutAttributes
}

var maxSizeForSelfSizing: ASOptionalSize
{
ASOptionalSize(
width: selfSizingConfig.canExceedCollectionWidth ? nil : collectionView.map { $0.contentSize.width - 0.001 },
height: selfSizingConfig.canExceedCollectionHeight ? nil : collectionView.map { $0.contentSize.height - 0.001 })
width: selfSizingConfig.canExceedCollectionWidth ? nil : collectionViewController.map { $0.collectionView.contentSize.width - 0.001 },
height: selfSizingConfig.canExceedCollectionHeight ? nil : collectionViewController.map { $0.collectionView.contentSize.height - 0.001 })
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ class ASCollectionViewDecoration<Content: Decoration>: ASCollectionViewSupplemen
override init(frame: CGRect)
{
super.init(frame: frame)
let view = Content()
hostingController = ASHostingController(view)
willAppear(in: nil)
hostingController = ASHostingController(Content())
willAppear()
}

required init?(coder: NSCoder)
Expand Down
Loading

0 comments on commit e71eda8

Please sign in to comment.