From 66a73f4c172e624db78bd335c2055a377a98f1c1 Mon Sep 17 00:00:00 2001 From: Dimitry Vinogradov Date: Sun, 16 Aug 2020 08:23:55 -0700 Subject: [PATCH 1/4] Add bool to configure scroll view insets --- .../PanModalPresentationController.swift | 2 +- .../Presentable/PanModalPresentable.swift | 137 +++++++++--------- .../Full Screen/FullScreenNavController.swift | 4 + 3 files changed, 77 insertions(+), 66 deletions(-) diff --git a/PanModal/Controller/PanModalPresentationController.swift b/PanModal/Controller/PanModalPresentationController.swift index 11fb2a6e..1e595a6c 100644 --- a/PanModal/Controller/PanModalPresentationController.swift +++ b/PanModal/Controller/PanModalPresentationController.swift @@ -440,7 +440,7 @@ private extension PanModalPresentationController { guard let scrollView = presentable?.panScrollable, - !scrollView.isScrolling + !scrollView.isScrolling && presentable?.shouldConfigureScrollViewInsets == true else { return } /** diff --git a/PanModal/Presentable/PanModalPresentable.swift b/PanModal/Presentable/PanModalPresentable.swift index 76c15015..cb8a4e1c 100644 --- a/PanModal/Presentable/PanModalPresentable.swift +++ b/PanModal/Presentable/PanModalPresentable.swift @@ -11,227 +11,234 @@ import UIKit /** This is the configuration object for a view controller that will be presented using the PanModal transition. - + Usage: ``` extension YourViewController: PanModalPresentable { - func shouldRoundTopCorners: Bool { return false } + func shouldRoundTopCorners: Bool { return false } } ``` */ public protocol PanModalPresentable: AnyObject { - + /** The scroll view embedded in the view controller. Setting this value allows for seamless transition scrolling between the embedded scroll view and the pan modal container view. */ var panScrollable: UIScrollView? { get } - + /** The offset between the top of the screen and the top of the pan modal container view. - + Default value is the topLayoutGuide.length + 21.0. */ var topOffset: CGFloat { get } - + /** The height of the pan modal container view when in the shortForm presentation state. - + This value is capped to .max, if provided value exceeds the space available. - + Default value is the longFormHeight. */ var shortFormHeight: PanModalHeight { get } - + /** The height of the pan modal container view when in the longForm presentation state. This value is capped to .max, if provided value exceeds the space available. - + Default value is .max. */ var longFormHeight: PanModalHeight { get } - + /** The corner radius used when `shouldRoundTopCorners` is enabled. - + Default Value is 8.0. */ var cornerRadius: CGFloat { get } - + /** The springDamping value used to determine the amount of 'bounce' seen when transitioning to short/long form. - + Default Value is 0.8. */ var springDamping: CGFloat { get } - + /** The transitionDuration value is used to set the speed of animation during a transition, including initial presentation. - + Default value is 0.5. - */ + */ var transitionDuration: Double { get } - + /** The animation options used when performing animations on the PanModal, utilized mostly during a transition. - + Default value is [.curveEaseInOut, .allowUserInteraction, .beginFromCurrentState]. - */ + */ var transitionAnimationOptions: UIView.AnimationOptions { get } - + /** The background view color. - + - Note: This is only utilized at the very start of the transition. - + Default Value is black with alpha component 0.7. - */ + */ var panModalBackgroundColor: UIColor { get } - + /** The drag indicator view color. - + Default value is light gray. - */ + */ var dragIndicatorBackgroundColor: UIColor { get } - + /** We configure the panScrollable's scrollIndicatorInsets interally so override this value to set custom insets. - + - Note: Use `panModalSetNeedsLayoutUpdate()` when updating insets. */ var scrollIndicatorInsets: UIEdgeInsets { get } - + /** A flag to determine if scrolling should be limited to the longFormHeight. Return false to cap scrolling at .max height. - + Default value is true. */ var anchorModalToLongForm: Bool { get } - + /** A flag to determine if scrolling should seamlessly transition from the pan modal container view to the embedded scroll view once the scroll limit has been reached. - + Default value is false. Unless a scrollView is provided and the content height exceeds the longForm height. */ var allowsExtendedPanScrolling: Bool { get } - + /** A flag to determine if dismissal should be initiated when swiping down on the presented view. - + Return false to fallback to the short form state instead of dismissing. - + Default value is true. */ var allowsDragToDismiss: Bool { get } - + /** A flag to determine if dismissal should be initiated when tapping on the dimmed background view. - + Default value is true. */ var allowsTapToDismiss: Bool { get } - + /** A flag to toggle user interactions on the container view. - + - Note: Return false to forward touches to the presentingViewController. - + Default is true. - */ + */ var isUserInteractionEnabled: Bool { get } - + /** A flag to determine if haptic feedback should be enabled during presentation. - + Default value is true. */ var isHapticFeedbackEnabled: Bool { get } - + /** A flag to determine if the top corners should be rounded. - + Default value is true. */ var shouldRoundTopCorners: Bool { get } - + /** A flag to determine if a drag indicator should be shown above the pan modal container view. - + Default value is true. */ var showDragIndicator: Bool { get } - + /** Asks the delegate if the pan modal should respond to the pan modal gesture recognizer. Return false to disable movement on the pan modal but maintain gestures on the presented view. - + Default value is true. */ func shouldRespond(to panModalGestureRecognizer: UIPanGestureRecognizer) -> Bool - + /** Notifies the delegate when the pan modal gesture recognizer state is either `began` or `changed`. This method gives the delegate a chance to prepare for the gesture recognizer state change. - + For example, when the pan modal view is about to scroll. - + Default value is an empty implementation. */ func willRespond(to panModalGestureRecognizer: UIPanGestureRecognizer) - + /** Asks the delegate if the pan modal gesture recognizer should be prioritized. - + For example, you can use this to define a region where you would like to restrict where the pan gesture can start. - + If false, then we rely solely on the internal conditions of when a pan gesture should succeed or fail, such as, if we're actively scrolling on the scrollView. - + Default return value is false. */ func shouldPrioritize(panModalGestureRecognizer: UIPanGestureRecognizer) -> Bool - + /** Asks the delegate if the pan modal should transition to a new state. - + Default value is true. */ func shouldTransition(to state: PanModalPresentationController.PresentationState) -> Bool - + /** Notifies the delegate that the pan modal is about to transition to a new state. - + Default value is an empty implementation. */ func willTransition(to state: PanModalPresentationController.PresentationState) - + /** Notifies the delegate that the pan modal is about to be dismissed. - + Default value is an empty implementation. */ func panModalWillDismiss() - + /** Notifies the delegate after the pan modal is dismissed. - + Default value is an empty implementation. */ func panModalDidDismiss() + + /** + Notifies the delegate after the pan modal is dismissed. + + Default value is an empty implementation. + */ + var shouldConfigureScrollViewInsets: Bool { get } } #endif diff --git a/Sample/View Controllers/Full Screen/FullScreenNavController.swift b/Sample/View Controllers/Full Screen/FullScreenNavController.swift index 9dbe6215..440e1ddc 100644 --- a/Sample/View Controllers/Full Screen/FullScreenNavController.swift +++ b/Sample/View Controllers/Full Screen/FullScreenNavController.swift @@ -45,6 +45,10 @@ extension FullScreenNavController: PanModalPresentable { var showDragIndicator: Bool { return false } + + var shouldConfigureScrollViewInsets: Bool { + return true + } } private class FullScreenViewController: UIViewController { From cb4ab0f7148d7809c4390b7635bbfad2e857c3a8 Mon Sep 17 00:00:00 2001 From: Dimitry Vinogradov Date: Sun, 16 Aug 2020 08:40:13 -0700 Subject: [PATCH 2/4] Track XOffset --- .../Controller/PanModalPresentationController.swift | 13 +++++++++++-- PanModal/Presentable/PanModalPresentable.swift | 8 ++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/PanModal/Controller/PanModalPresentationController.swift b/PanModal/Controller/PanModalPresentationController.swift index 1e595a6c..2416e4eb 100644 --- a/PanModal/Controller/PanModalPresentationController.swift +++ b/PanModal/Controller/PanModalPresentationController.swift @@ -66,6 +66,11 @@ open class PanModalPresentationController: UIPresentationController { The y content offset value of the embedded scroll view */ private var scrollViewYOffset: CGFloat = 0.0 + + /** + The y content offset value of the embedded scroll view + */ + private var scrollViewXOffset: CGFloat = 0.0 /** An observer for the scroll view content offset @@ -759,7 +764,7 @@ private extension PanModalPresentationController { Halts the scroll of a given scroll view & anchors it at the `scrollViewYOffset` */ func haltScrolling(_ scrollView: UIScrollView) { - scrollView.setContentOffset(CGPoint(x: 0, y: scrollViewYOffset), animated: false) + scrollView.setContentOffset(CGPoint(x: scrollViewXOffset, y: scrollViewYOffset), animated: false) scrollView.showsVerticalScrollIndicator = false } @@ -769,7 +774,11 @@ private extension PanModalPresentationController { */ func trackScrolling(_ scrollView: UIScrollView) { scrollViewYOffset = max(scrollView.contentOffset.y, 0) - scrollView.showsVerticalScrollIndicator = true + scrollViewXOffset = max(scrollView.contentOffset.x, 0) + + if presentable?.shouldConfigureScrollViewInsets == true { + scrollView.showsVerticalScrollIndicator = true + } } /** diff --git a/PanModal/Presentable/PanModalPresentable.swift b/PanModal/Presentable/PanModalPresentable.swift index cb8a4e1c..c26cca77 100644 --- a/PanModal/Presentable/PanModalPresentable.swift +++ b/PanModal/Presentable/PanModalPresentable.swift @@ -235,9 +235,13 @@ public protocol PanModalPresentable: AnyObject { func panModalDidDismiss() /** - Notifies the delegate after the pan modal is dismissed. + A flag to determine if the scroll view embedded in the pan modal should have + its insets configured automatically. - Default value is an empty implementation. + For example, scroll views that do not occupy the bounds of the pan modal may + need different insets set instead of the defaults. + + Default value is true. */ var shouldConfigureScrollViewInsets: Bool { get } } From 9119d72dcf94345686246478f7487b322ab0309b Mon Sep 17 00:00:00 2001 From: Dimitry Vinogradov Date: Sun, 16 Aug 2020 09:25:49 -0700 Subject: [PATCH 3/4] Add ability to halt scroll --- PanModal/Controller/PanModalPresentationController.swift | 1 + PanModal/Presentable/PanModalPresentable.swift | 2 ++ .../Full Screen/FullScreenNavController.swift | 4 ++++ 3 files changed, 7 insertions(+) diff --git a/PanModal/Controller/PanModalPresentationController.swift b/PanModal/Controller/PanModalPresentationController.swift index 2416e4eb..6ff7b1ab 100644 --- a/PanModal/Controller/PanModalPresentationController.swift +++ b/PanModal/Controller/PanModalPresentationController.swift @@ -764,6 +764,7 @@ private extension PanModalPresentationController { Halts the scroll of a given scroll view & anchors it at the `scrollViewYOffset` */ func haltScrolling(_ scrollView: UIScrollView) { + guard presentable?.shouldHaltScroll != false else { return } scrollView.setContentOffset(CGPoint(x: scrollViewXOffset, y: scrollViewYOffset), animated: false) scrollView.showsVerticalScrollIndicator = false } diff --git a/PanModal/Presentable/PanModalPresentable.swift b/PanModal/Presentable/PanModalPresentable.swift index c26cca77..c8b18d11 100644 --- a/PanModal/Presentable/PanModalPresentable.swift +++ b/PanModal/Presentable/PanModalPresentable.swift @@ -244,5 +244,7 @@ public protocol PanModalPresentable: AnyObject { Default value is true. */ var shouldConfigureScrollViewInsets: Bool { get } + + var shouldHaltScroll: Bool { get } } #endif diff --git a/Sample/View Controllers/Full Screen/FullScreenNavController.swift b/Sample/View Controllers/Full Screen/FullScreenNavController.swift index 440e1ddc..e7d98c00 100644 --- a/Sample/View Controllers/Full Screen/FullScreenNavController.swift +++ b/Sample/View Controllers/Full Screen/FullScreenNavController.swift @@ -49,6 +49,10 @@ extension FullScreenNavController: PanModalPresentable { var shouldConfigureScrollViewInsets: Bool { return true } + + var shouldHaltScroll: Bool { + return true + } } private class FullScreenViewController: UIViewController { From 7f7a969d7c9375b1164c62dd56ad42b59db947a5 Mon Sep 17 00:00:00 2001 From: Dimitry Vinogradov Date: Wed, 7 Oct 2020 14:55:37 -0700 Subject: [PATCH 4/4] Comments --- PanModal/Controller/PanModalPresentationController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PanModal/Controller/PanModalPresentationController.swift b/PanModal/Controller/PanModalPresentationController.swift index 6ff7b1ab..27f9cdc0 100644 --- a/PanModal/Controller/PanModalPresentationController.swift +++ b/PanModal/Controller/PanModalPresentationController.swift @@ -68,7 +68,7 @@ open class PanModalPresentationController: UIPresentationController { private var scrollViewYOffset: CGFloat = 0.0 /** - The y content offset value of the embedded scroll view + The x content offset value of the embedded scroll view */ private var scrollViewXOffset: CGFloat = 0.0