diff --git a/Examples/Samples/Samples.xcodeproj/project.pbxproj b/Examples/Samples/Samples.xcodeproj/project.pbxproj index 38fcb77e..3ddace28 100644 --- a/Examples/Samples/Samples.xcodeproj/project.pbxproj +++ b/Examples/Samples/Samples.xcodeproj/project.pbxproj @@ -18,7 +18,7 @@ 5442E24A25FC53C100A26F43 /* DebugTextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5442E24925FC53C100A26F43 /* DebugTextViewController.swift */; }; 5442E25225FC541700A26F43 /* NestedScrollViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5442E25125FC541700A26F43 /* NestedScrollViewController.swift */; }; 54496C59263A7E5A0031E0C8 /* UseCaseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54496C58263A7E5A0031E0C8 /* UseCaseController.swift */; }; - 544BC56826CC918200D0A436 /* AdaptiveLayoutTestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 544BC56726CC918200D0A436 /* AdaptiveLayoutTestViewController.swift */; }; + 544BC56826CC918200D0A436 /* TableViewControllerForAdaptiveLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 544BC56726CC918200D0A436 /* TableViewControllerForAdaptiveLayout.swift */; }; 545DB9EE21511E6300CA77B8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545DB9ED21511E6300CA77B8 /* AppDelegate.swift */; }; 545DB9F021511E6300CA77B8 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545DB9EF21511E6300CA77B8 /* MainViewController.swift */; }; 545DB9F321511E6300CA77B8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 545DB9F121511E6300CA77B8 /* Main.storyboard */; }; @@ -30,6 +30,7 @@ 549D23CC233C7779008EF4D7 /* FloatingPanel.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 549D23CA233C7779008EF4D7 /* FloatingPanel.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 54B51116216AFE5F0033A6F3 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54B51115216AFE5F0033A6F3 /* Extensions.swift */; }; 54CDC5D8215BBE23007D205C /* SupplementaryViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CDC5D7215BBE23007D205C /* SupplementaryViews.swift */; }; + 54E58CB72BF8A8D900408EA9 /* CollectionViewControllerForAdaptiveLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E58CB62BF8A8D900408EA9 /* CollectionViewControllerForAdaptiveLayout.swift */; }; 54EAD35B263A75EB006A36EA /* PanelLayouts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54EAD35A263A75EB006A36EA /* PanelLayouts.swift */; }; 54EAD365263A765F006A36EA /* PagePanelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54EAD364263A765F006A36EA /* PagePanelController.swift */; }; 54F185822BF4AD0000916F57 /* DebugListCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54F185812BF4AD0000916F57 /* DebugListCollectionViewController.swift */; }; @@ -63,7 +64,7 @@ 5442E24925FC53C100A26F43 /* DebugTextViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugTextViewController.swift; sourceTree = ""; }; 5442E25125FC541700A26F43 /* NestedScrollViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedScrollViewController.swift; sourceTree = ""; }; 54496C58263A7E5A0031E0C8 /* UseCaseController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UseCaseController.swift; sourceTree = ""; }; - 544BC56726CC918200D0A436 /* AdaptiveLayoutTestViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdaptiveLayoutTestViewController.swift; sourceTree = ""; }; + 544BC56726CC918200D0A436 /* TableViewControllerForAdaptiveLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewControllerForAdaptiveLayout.swift; sourceTree = ""; }; 545DB9EA21511E6300CA77B8 /* Samples.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Samples.app; sourceTree = BUILT_PRODUCTS_DIR; }; 545DB9ED21511E6300CA77B8 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 545DB9EF21511E6300CA77B8 /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; @@ -76,6 +77,7 @@ 549D23CA233C7779008EF4D7 /* FloatingPanel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = FloatingPanel.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 54B51115216AFE5F0033A6F3 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; 54CDC5D7215BBE23007D205C /* SupplementaryViews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupplementaryViews.swift; sourceTree = ""; }; + 54E58CB62BF8A8D900408EA9 /* CollectionViewControllerForAdaptiveLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewControllerForAdaptiveLayout.swift; sourceTree = ""; }; 54EAD35A263A75EB006A36EA /* PanelLayouts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PanelLayouts.swift; sourceTree = ""; }; 54EAD364263A765F006A36EA /* PagePanelController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PagePanelController.swift; sourceTree = ""; }; 54F185812BF4AD0000916F57 /* DebugListCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugListCollectionViewController.swift; sourceTree = ""; }; @@ -99,18 +101,17 @@ 5442E22225FC519700A26F43 /* ContentViewControllers */ = { isa = PBXGroup; children = ( + 54E58CB52BF8A88600408EA9 /* AdaptiveLayout */, 5442E23F25FC533800A26F43 /* DebugTableViewController.swift */, 5442E24925FC53C100A26F43 /* DebugTextViewController.swift */, 54F185812BF4AD0000916F57 /* DebugListCollectionViewController.swift */, 5442E23325FC528400A26F43 /* DetailViewController.swift */, 5442E24325FC538200A26F43 /* InspectorViewController.swift */, - 5442E22325FC51AF00A26F43 /* ImageViewController.swift */, 5442E25125FC541700A26F43 /* NestedScrollViewController.swift */, 5442E23925FC52CD00A26F43 /* ModalViewController.swift */, 5442E22725FC51E200A26F43 /* MultiPanelController.swift */, 5442E22B25FC521F00A26F43 /* SettingsViewController.swift */, 5442E22F25FC525200A26F43 /* TabBarViewController.swift */, - 544BC56726CC918200D0A436 /* AdaptiveLayoutTestViewController.swift */, 54F185832BF4B82E00916F57 /* UnavailableViewController.swift */, ); path = ContentViewControllers; @@ -163,6 +164,16 @@ path = UseCases; sourceTree = ""; }; + 54E58CB52BF8A88600408EA9 /* AdaptiveLayout */ = { + isa = PBXGroup; + children = ( + 5442E22325FC51AF00A26F43 /* ImageViewController.swift */, + 544BC56726CC918200D0A436 /* TableViewControllerForAdaptiveLayout.swift */, + 54E58CB62BF8A8D900408EA9 /* CollectionViewControllerForAdaptiveLayout.swift */, + ); + path = AdaptiveLayout; + sourceTree = ""; + }; 5D82A6AB28D18438006A44BA /* Frameworks */ = { isa = PBXGroup; children = ( @@ -244,10 +255,11 @@ buildActionMask = 2147483647; files = ( 5442E23425FC528400A26F43 /* DetailViewController.swift in Sources */, + 54E58CB72BF8A8D900408EA9 /* CollectionViewControllerForAdaptiveLayout.swift in Sources */, 54496C59263A7E5A0031E0C8 /* UseCaseController.swift in Sources */, 54CDC5D8215BBE23007D205C /* SupplementaryViews.swift in Sources */, 54B51116216AFE5F0033A6F3 /* Extensions.swift in Sources */, - 544BC56826CC918200D0A436 /* AdaptiveLayoutTestViewController.swift in Sources */, + 544BC56826CC918200D0A436 /* TableViewControllerForAdaptiveLayout.swift in Sources */, 5442E24A25FC53C100A26F43 /* DebugTextViewController.swift in Sources */, 546341AC25C6426500CA0596 /* CustomState.swift in Sources */, 5442E23A25FC52CD00A26F43 /* ModalViewController.swift in Sources */, diff --git a/Examples/Samples/Sources/Base.lproj/Main.storyboard b/Examples/Samples/Sources/Base.lproj/Main.storyboard index 0859c7f5..25e176b5 100644 --- a/Examples/Samples/Sources/Base.lproj/Main.storyboard +++ b/Examples/Samples/Sources/Base.lproj/Main.storyboard @@ -1,9 +1,9 @@ - + - + @@ -801,10 +801,10 @@ Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC - + - + @@ -861,13 +861,13 @@ Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC - + - + - + diff --git a/Examples/Samples/Sources/ContentViewControllers/AdaptiveLayout/CollectionViewControllerForAdaptiveLayout.swift b/Examples/Samples/Sources/ContentViewControllers/AdaptiveLayout/CollectionViewControllerForAdaptiveLayout.swift new file mode 100644 index 00000000..bfe8b798 --- /dev/null +++ b/Examples/Samples/Sources/ContentViewControllers/AdaptiveLayout/CollectionViewControllerForAdaptiveLayout.swift @@ -0,0 +1,175 @@ +// Copyright 2018-Present Shin Yamamoto. All rights reserved. MIT license. + +import UIKit +import FloatingPanel + +@available(iOS 13.0, *) +class CollectionViewControllerForAdaptiveLayout: UIViewController { + class PanelLayout: FloatingPanelLayout { + let position: FloatingPanelPosition = .bottom + let initialState: FloatingPanelState = .full + + private unowned var targetGuide: UILayoutGuide + + init(targetGuide: UILayoutGuide) { + self.targetGuide = targetGuide + } + + var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] { + return [ + .full: FloatingPanelAdaptiveLayoutAnchor( + absoluteOffset: 0.0, + contentLayout: targetGuide, + referenceGuide: .superview, + contentBoundingGuide: .safeArea + ), + .half: FloatingPanelAdaptiveLayoutAnchor( + fractionalOffset: 0.5, + contentLayout: targetGuide, + referenceGuide: .superview, + contentBoundingGuide: .safeArea + ), + ] + } + } + + enum LayoutType { + case flow + case compositional + } + + weak var collectionView: UICollectionView! + var layoutType: LayoutType = .flow + + override func viewDidLoad() { + super.viewDidLoad() + setupCollectionView() + } + + private func setupCollectionView() { + let collectionViewLayout = { + switch layoutType { + case .flow: + CollectionViewLayoutFactory.flowLayout + case .compositional: + CollectionViewLayoutFactory.compositionalLayout + } + }() + let collectionView = IntrinsicCollectionView( + frame: .zero, + collectionViewLayout: collectionViewLayout + ) + + collectionView.delegate = self + collectionView.dataSource = self + collectionView.backgroundColor = .yellow + collectionView.register(Cell.self, forCellWithReuseIdentifier: Cell.reuseIdentifier) + + view.addSubview(collectionView) + self.collectionView = collectionView + + collectionView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + collectionView.topAnchor.constraint(equalTo: view.topAnchor), + collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor) + ]) + } +} + +@available(iOS 13.0, *) +extension CollectionViewControllerForAdaptiveLayout: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return 5 // Only three cells needed to fill the space + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Cell.reuseIdentifier, for: indexPath) as! Cell + cell.configure(text: "Item \(indexPath.row)") + return cell + } + + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + let width = collectionView.frame.width + return CGSize(width: width, height: 100) + } +} + +@available(iOS 13.0, *) +extension CollectionViewControllerForAdaptiveLayout { + enum CollectionViewLayoutFactory { + static var flowLayout: UICollectionViewLayout { + let layout = UICollectionViewFlowLayout() + layout.scrollDirection = .vertical + layout.minimumLineSpacing = 8 // Vertical spacing between rows + return layout + } + + @available(iOS 13.0, *) + static var compositionalLayout: UICollectionViewLayout { + UICollectionViewCompositionalLayout { (sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in + let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(100)) + let item = NSCollectionLayoutItem(layoutSize: itemSize) + + let group = NSCollectionLayoutGroup.horizontal(layoutSize: itemSize, subitems: [item]) + + let section = NSCollectionLayoutSection(group: group) + section.interGroupSpacing = 8 // Spacing between each group/item + section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0) + + return section + } + } + } + + + private final class Cell: UICollectionViewCell { + static let reuseIdentifier = "Cell" + + private let label: UILabel = { + let label = UILabel() + label.textAlignment = .center + label.textColor = .white + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + commonInit() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + commonInit() + } + + private func commonInit() { + backgroundColor = .systemBlue + addSubview(label) + label.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + label.centerXAnchor.constraint(equalTo: centerXAnchor), + label.centerYAnchor.constraint(equalTo: centerYAnchor) + ]) + } + + func configure(text: String) { + label.text = text + } + } + + private final class IntrinsicCollectionView: UICollectionView { + override public var contentSize: CGSize { + didSet { + invalidateIntrinsicContentSize() + } + } + + override public var intrinsicContentSize: CGSize { + layoutIfNeeded() + return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height) + } + } +} diff --git a/Examples/Samples/Sources/ContentViewControllers/ImageViewController.swift b/Examples/Samples/Sources/ContentViewControllers/AdaptiveLayout/ImageViewController.swift similarity index 100% rename from Examples/Samples/Sources/ContentViewControllers/ImageViewController.swift rename to Examples/Samples/Sources/ContentViewControllers/AdaptiveLayout/ImageViewController.swift diff --git a/Examples/Samples/Sources/ContentViewControllers/AdaptiveLayoutTestViewController.swift b/Examples/Samples/Sources/ContentViewControllers/AdaptiveLayout/TableViewControllerForAdaptiveLayout.swift similarity index 95% rename from Examples/Samples/Sources/ContentViewControllers/AdaptiveLayoutTestViewController.swift rename to Examples/Samples/Sources/ContentViewControllers/AdaptiveLayout/TableViewControllerForAdaptiveLayout.swift index a87a7fcf..4b2f4d9d 100644 --- a/Examples/Samples/Sources/ContentViewControllers/AdaptiveLayoutTestViewController.swift +++ b/Examples/Samples/Sources/ContentViewControllers/AdaptiveLayout/TableViewControllerForAdaptiveLayout.swift @@ -3,7 +3,7 @@ import UIKit import FloatingPanel -final class AdaptiveLayoutTestViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { +final class TableViewControllerForAdaptiveLayout: UIViewController, UITableViewDataSource, UITableViewDelegate { class PanelLayout: FloatingPanelLayout { let position: FloatingPanelPosition = .bottom let initialState: FloatingPanelState = .full @@ -75,7 +75,6 @@ final class AdaptiveLayoutTestViewController: UIViewController, UITableViewDataS } class IntrinsicTableView: UITableView { - override var contentSize:CGSize { didSet { invalidateIntrinsicContentSize() diff --git a/Examples/Samples/Sources/UseCases/UseCase.swift b/Examples/Samples/Sources/UseCases/UseCase.swift index 42d843f7..14fbe8e5 100644 --- a/Examples/Samples/Sources/UseCases/UseCase.swift +++ b/Examples/Samples/Sources/UseCases/UseCase.swift @@ -23,7 +23,9 @@ enum UseCase: Int, CaseIterable { case showNavigationController case showTopPositionedPanel case showAdaptivePanel - case showAdaptivePanelWithCustomGuide + case showAdaptivePanelWithTableView + case showAdaptivePanelWithCollectionView + case showAdaptivePanelWithCompositionalCollectionView case showCustomStatePanel case showCustomBackdrop } @@ -51,7 +53,9 @@ extension UseCase { case .showNavigationController: return "Show Navigation Controller" case .showTopPositionedPanel: return "Show Top Positioned Panel" case .showAdaptivePanel: return "Show Adaptive Panel" - case .showAdaptivePanelWithCustomGuide: return "Show Adaptive Panel (Custom Layout Guide)" + case .showAdaptivePanelWithTableView: return "Show Adaptive Panel (TableView)" + case .showAdaptivePanelWithCollectionView: return "Show Adaptive Panel (CollectionView)" + case .showAdaptivePanelWithCompositionalCollectionView: return "Show Adaptive Panel (Compositional CollectionView)" case .showCustomStatePanel: return "Show Panel with Custom state" case .showCustomBackdrop: return "Show Panel with Custom Backdrop" } @@ -71,10 +75,8 @@ extension UseCase { if #available(iOS 14, *) { return .viewController(DebugListCollectionViewController()) } else { - let vc = UnavailableViewController() - vc.loadViewIfNeeded() - vc.label.text = "UICollectionLayoutListConfiguration is unavailable.\nBuild this app on iOS 14 and later." - return .viewController(vc) + let msg = "UICollectionLayoutListConfiguration is unavailable.\nBuild this app on iOS 14 and later." + return makeUnavailableViewContent(message: msg) } case .trackingTextView: return .storyboard("ConsoleViewController") // Storyboard only case .showDetail: return .storyboard(String(describing: DetailViewController.self)) @@ -94,7 +96,17 @@ extension UseCase { case .showNavigationController: return .storyboard("RootNavigationController") // Storyboard only case .showTopPositionedPanel: return .viewController(DebugTableViewController()) case .showAdaptivePanel: return .storyboard(String(describing: ImageViewController.self)) - case .showAdaptivePanelWithCustomGuide: return .storyboard(String(describing: AdaptiveLayoutTestViewController.self)) + case .showAdaptivePanelWithTableView: return .storyboard(String(describing: TableViewControllerForAdaptiveLayout.self)) + case .showAdaptivePanelWithCollectionView, + .showAdaptivePanelWithCompositionalCollectionView: + if #available(iOS 13, *) { + let vc = CollectionViewControllerForAdaptiveLayout() + vc.layoutType = self == .showAdaptivePanelWithCollectionView ? .flow : .compositional + return .viewController(vc) + } else { + let msg = "Compositional layout is unavailable.\nBuild this app on iOS 13 and later." + return makeUnavailableViewContent(message: msg) + } case .showCustomStatePanel: return .viewController(DebugTableViewController()) case .showCustomBackdrop: return .viewController(UIViewController()) } @@ -109,4 +121,11 @@ extension UseCase { return vc } } + + private func makeUnavailableViewContent(message: String) -> Content { + let vc = UnavailableViewController() + vc.loadViewIfNeeded() + vc.label.text = message + return .viewController(vc) + } } diff --git a/Examples/Samples/Sources/UseCases/UseCaseController.swift b/Examples/Samples/Sources/UseCases/UseCaseController.swift index 5cddf6ba..4e1ac686 100644 --- a/Examples/Samples/Sources/UseCases/UseCaseController.swift +++ b/Examples/Samples/Sources/UseCases/UseCaseController.swift @@ -263,13 +263,13 @@ extension UseCaseController { fpc.set(contentViewController: contentVC) fpc.ext_trackScrollView(in: contentVC) if case let contentVC as ImageViewController = contentVC { - let mode: ImageViewController.Mode = (useCase == .showAdaptivePanelWithCustomGuide) ? .withHeaderFooter : .onlyImage + let mode: ImageViewController.Mode = (useCase == .showAdaptivePanelWithTableView) ? .withHeaderFooter : .onlyImage let layoutGuide = contentVC.layoutGuideFor(mode: mode) fpc.layout = ImageViewController.PanelLayout(targetGuide: layoutGuide) } addMain(panel: fpc) - case .showAdaptivePanelWithCustomGuide: + case .showAdaptivePanelWithTableView: let fpc = FloatingPanelController() fpc.isRemovalInteractionEnabled = true fpc.contentInsetAdjustmentBehavior = .always @@ -279,10 +279,25 @@ extension UseCaseController { return appearance }() + fpc.set(contentViewController: contentVC) + fpc.track(scrollView: (contentVC as! TableViewControllerForAdaptiveLayout).tableView) + fpc.layout = TableViewControllerForAdaptiveLayout.PanelLayout(targetGuide: contentVC.view.makeBoundsLayoutGuide()) + addMain(panel: fpc) + case .showAdaptivePanelWithCollectionView, .showAdaptivePanelWithCompositionalCollectionView: + let fpc = FloatingPanelController() + fpc.isRemovalInteractionEnabled = true + fpc.contentInsetAdjustmentBehavior = .always + fpc.surfaceView.appearance = { + let appearance = SurfaceAppearance() + appearance.cornerRadius = 6.0 + return appearance + }() fpc.set(contentViewController: contentVC) - fpc.ext_trackScrollView(in: contentVC) - fpc.layout = AdaptiveLayoutTestViewController.PanelLayout(targetGuide: contentVC.view.makeBoundsLayoutGuide()) + if #available(iOS 13, *) { + fpc.track(scrollView: (contentVC as! CollectionViewControllerForAdaptiveLayout).collectionView) + fpc.layout = CollectionViewControllerForAdaptiveLayout.PanelLayout(targetGuide: contentVC.view.makeBoundsLayoutGuide()) + } addMain(panel: fpc) case .showCustomStatePanel: @@ -482,7 +497,7 @@ private extension FloatingPanelController { case let contentVC as ImageViewController: track(scrollView: contentVC.scrollView) - case let contentVC as AdaptiveLayoutTestViewController: + case let contentVC as TableViewControllerForAdaptiveLayout: track(scrollView: contentVC.tableView) default: diff --git a/Sources/SurfaceView.swift b/Sources/SurfaceView.swift index 31d1d63e..396bb86b 100644 --- a/Sources/SurfaceView.swift +++ b/Sources/SurfaceView.swift @@ -418,12 +418,30 @@ public class SurfaceView: UIView { let leftConstraint = contentView.leftAnchor.constraint(equalTo: leftAnchor, constant: containerMargins.left + contentPadding.left) let rightConstraint = rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: containerMargins.right + contentPadding.right) let bottomConstraint = bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: containerMargins.bottom + contentPadding.bottom) - NSLayoutConstraint.activate([ + + var constraints = [ topConstraint, leftConstraint, rightConstraint, - bottomConstraint, - ].map { + bottomConstraint + ] + + // This constraint is for UICollectionView using UICollectionViewCompositionalLayout. + // It's seemingly obvious, but the UICollectionView doesn't work without setting it. (#628) + switch position { + case .top, .bottom: + constraints += [ + heightAnchor.constraint(greaterThanOrEqualToConstant: 1.0) + ] + case .left, .right: + constraints += [ + widthAnchor.constraint(greaterThanOrEqualToConstant: 1.0) + ] + } + + NSLayoutConstraint.activate( + constraints + .map { switch mode { case .static: $0.priority = .required