diff --git a/SheetImagePicker/SheetContainerViewController.swift b/SheetImagePicker/SheetContainerViewController.swift
index a6fd8c1..99f0669 100644
--- a/SheetImagePicker/SheetContainerViewController.swift
+++ b/SheetImagePicker/SheetContainerViewController.swift
@@ -11,6 +11,8 @@ import UIKit
public protocol SheetContainerViewControllerDelegate {
func sheetContainer(_ sheetContainer: SheetContainerViewController, willSnapToDetent detent: Detent) -> Bool
func sheetContainer(_ sheetContainer: SheetContainerViewController, didSnapToDetent detent: Detent)
+ func sheetContainerContentScrollView(_ sheetContainer: SheetContainerViewController) -> UIScrollView?
+ func sheetContainer(_ sheetContainer: SheetContainerViewController, topContentOffsetForScrollView scrollView: UIScrollView) -> CGFloat
}
// default no-op implementation
@@ -19,13 +21,19 @@ public extension SheetContainerViewControllerDelegate {
return true
}
func sheetContainer(_ sheetContainer: SheetContainerViewController, didSnapToDetent detent: Detent) {}
+ func sheetContainerContentScrollView(_ sheetContainer: SheetContainerViewController) -> UIScrollView? {
+ return nil
+ }
+ func sheetContainer(_ sheetContainer: SheetContainerViewController, topContentOffsetForScrollView scrollView: UIScrollView) -> CGFloat {
+ return 0
+ }
}
public class SheetContainerViewController: UIViewController {
public var delegate: SheetContainerViewControllerDelegate?
- let content: UIViewController
+ public let content: UIViewController
public var detents: [Detent] = [.bottom, .middle, .top]
var topDetent: (detent: Detent, offset: CGFloat) {
@@ -44,7 +52,10 @@ public class SheetContainerViewController: UIViewController {
var dimmingView: UIView!
public var minimumDimmingAlpha: CGFloat = 0
public var maximumDimmingAlpha: CGFloat = 0.75
- var initialScrollViewContentOffset = CGPoint.zero
+
+ var contentScrollView: UIScrollView? {
+ delegate?.sheetContainerContentScrollView(self) ?? content.view as? UIScrollView
+ }
public init(content: UIViewController) {
self.content = content
@@ -85,11 +96,12 @@ public class SheetContainerViewController: UIViewController {
dimmingView.bottomAnchor.constraint(equalTo: content.view.topAnchor, constant: content.view.layer.cornerRadius)
])
- if let scrollView = content.view as? UIScrollView {
+ let panGesture = UIPanGestureRecognizer(target: self, action: #selector(panGestureRecognized(_:)))
+ panGesture.delegate = self
+ content.view.addGestureRecognizer(panGesture)
+
+ if let scrollView = contentScrollView {
scrollView.panGestureRecognizer.addTarget(self, action: #selector(scrollViewPanGestureRecognized))
- } else {
- let panGesture = UIPanGestureRecognizer(target: self, action: #selector(panGestureRecognized(_:)))
- content.view.addGestureRecognizer(panGesture)
}
}
@@ -114,29 +126,27 @@ public class SheetContainerViewController: UIViewController {
@objc func scrollViewPanGestureRecognized(_ recognizer: UIPanGestureRecognizer) {
guard let scrollView = recognizer.view as? UIScrollView else { return }
-
- let translation = recognizer.translation(in: scrollView)
+
let velocity = recognizer.velocity(in: scrollView)
-
- let shouldMoveSheetDown = scrollView.contentOffset.y <= 0 && velocity.y > 0 // scrolled to top and dragging down
+
+ let topContentOffset: CGFloat = delegate?.sheetContainer(self, topContentOffsetForScrollView: scrollView) ?? 0
+ let shouldMoveSheetDown = scrollView.contentOffset.y <= topContentOffset && velocity.y > 0 // scrolled to top and dragging down
let shouldMoveSheetUp = topConstraint.constant > topDetent.offset && velocity.y < 0 // not fully expanded and dragging up
-
+
let shouldMoveSheet = shouldMoveSheetDown || shouldMoveSheetUp
if shouldMoveSheet {
scrollView.bounces = false
- scrollView.setContentOffset(.zero, animated: false)
+ scrollView.setContentOffset(CGPoint(x: 0, y: topContentOffset), animated: false)
}
-
+
switch recognizer.state {
- case .began:
- initialScrollViewContentOffset = scrollView.contentOffset
-
case .changed:
if shouldMoveSheet {
+ let translation = recognizer.translation(in: scrollView)
setTopOffset(topConstraint.constant + translation.y)
- recognizer.setTranslation(initialScrollViewContentOffset, in: scrollView)
+ recognizer.setTranslation(.zero, in: scrollView)
}
-
+
case .ended:
scrollView.bounces = true
if shouldMoveSheet {
@@ -205,6 +215,15 @@ public class SheetContainerViewController: UIViewController {
}
+extension SheetContainerViewController: UIGestureRecognizerDelegate {
+ public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
+ if topConstraint.constant <= topDetent.offset {
+ return (gestureRecognizer as! UIPanGestureRecognizer).translation(in: gestureRecognizer.view!).y > 0
+ }
+ return true
+ }
+}
+
extension SheetContainerViewController: UIViewControllerTransitioningDelegate {
public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return SheetContainerPresentationAnimationController()
diff --git a/SheetImagePickerTest/Base.lproj/Main.storyboard b/SheetImagePickerTest/Base.lproj/Main.storyboard
index 78619f3..450ea98 100644
--- a/SheetImagePickerTest/Base.lproj/Main.storyboard
+++ b/SheetImagePickerTest/Base.lproj/Main.storyboard
@@ -16,29 +16,36 @@
-
+
+
diff --git a/SheetImagePickerTest/ContentTableViewController.swift b/SheetImagePickerTest/ContentTableViewController.swift
index e1c60cb..75a5654 100644
--- a/SheetImagePickerTest/ContentTableViewController.swift
+++ b/SheetImagePickerTest/ContentTableViewController.swift
@@ -40,4 +40,21 @@ class ContentTableViewController: UITableViewController {
return cell
}
+
+ override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ guard let navController = navigationController else { return }
+
+ let vc = UIViewController()
+ vc.view.backgroundColor = .systemBackground
+ let label = UILabel()
+ label.translatesAutoresizingMaskIntoConstraints = false
+ label.text = "\(indexPath.row)"
+ vc.view.addSubview(label)
+ NSLayoutConstraint.activate([
+ label.centerXAnchor.constraint(equalTo: vc.view.centerXAnchor),
+ label.centerYAnchor.constraint(equalTo: vc.view.centerYAnchor)
+ ])
+
+ navController.pushViewController(vc, animated: true)
+ }
}
diff --git a/SheetImagePickerTest/ViewController.swift b/SheetImagePickerTest/ViewController.swift
index 69e8044..5adba45 100644
--- a/SheetImagePickerTest/ViewController.swift
+++ b/SheetImagePickerTest/ViewController.swift
@@ -58,6 +58,42 @@ class ViewController: UIViewController {
}
@IBAction func navPressed(_ sender: Any) {
+ let root = UIViewController()
+ root.view.backgroundColor = .systemBackground
+ let label = UILabel()
+ label.text = "Root VC"
+ label.translatesAutoresizingMaskIntoConstraints = false
+ root.view.addSubview(label)
+ NSLayoutConstraint.activate([
+ label.centerXAnchor.constraint(equalTo: root.view.centerXAnchor),
+ label.centerYAnchor.constraint(equalTo: root.view.centerYAnchor)
+ ])
+
+ let nav = UINavigationController(rootViewController: root)
+ nav.view.translatesAutoresizingMaskIntoConstraints = false
+ nav.view.layer.masksToBounds = true
+ nav.view.layer.cornerRadius = view.bounds.width * 0.02
+
+ let sheet = SheetContainerViewController(content: nav)
+ sheet.delegate = self
+ sheet.detents = [.bottom, .middle, .top]
+
+ present(sheet, animated: true)
+ }
+
+ @IBAction func navTablePressed(_ sender: Any) {
+ let table = ContentTableViewController()
+
+ let nav = UINavigationController(rootViewController: table)
+ nav.view.translatesAutoresizingMaskIntoConstraints = false
+ nav.view.layer.masksToBounds = true
+ nav.view.layer.cornerRadius = view.bounds.width * 0.02
+
+ let sheet = SheetContainerViewController(content: nav)
+ sheet.delegate = self
+ sheet.detents = [.bottom, .middle, .top]
+
+ present(sheet, animated: true)
}
}
@@ -69,4 +105,18 @@ extension ViewController: SheetContainerViewControllerDelegate {
}
return true
}
+ func sheetContainerContentScrollView(_ sheetContainer: SheetContainerViewController) -> UIScrollView? {
+ if let navController = sheetContainer.content as? UINavigationController, let scrollView = navController.visibleViewController?.view as? UIScrollView {
+ return scrollView
+ } else {
+ return nil
+ }
+ }
+ func sheetContainer(_ sheetContainer: SheetContainerViewController, topContentOffsetForScrollView scrollView: UIScrollView) -> CGFloat {
+ if let navController = sheetContainer.content as? UINavigationController, navController.visibleViewController?.view is UIScrollView {
+ return -navController.navigationBar.bounds.height
+ } else {
+ return 0
+ }
+ }
}