From c672bf1b3288e1e3de90f3e5a486841b53cf4fef Mon Sep 17 00:00:00 2001 From: Brendan Lee Date: Tue, 20 Sep 2016 22:06:24 -0400 Subject: [PATCH 1/4] Add support for disabling / enabling drawer positions. --- Pulley/DrawerContentViewController.swift | 4 + PulleyLib/PulleyViewController.swift | 141 ++++++++++++++++++++--- 2 files changed, 129 insertions(+), 16 deletions(-) diff --git a/Pulley/DrawerContentViewController.swift b/Pulley/DrawerContentViewController.swift index eedc14b..ead5e2a 100644 --- a/Pulley/DrawerContentViewController.swift +++ b/Pulley/DrawerContentViewController.swift @@ -70,6 +70,10 @@ class DrawerContentViewController: UIViewController, UITableViewDelegate, UITabl { return 264.0 } + + func supportedDrawerPositions() -> [PulleyPosition] { + return PulleyPosition.all // You can specify the drawer positions you support. This is the same as: [.open, .partiallyRevealed, .collapsed] + } func drawerPositionDidChange(drawer: PulleyViewController) { diff --git a/PulleyLib/PulleyViewController.swift b/PulleyLib/PulleyViewController.swift index f7f70ca..19b3400 100644 --- a/PulleyLib/PulleyViewController.swift +++ b/PulleyLib/PulleyViewController.swift @@ -21,16 +21,17 @@ import UIKit /** * View controllers in the drawer can implement this to receive changes in state or provide values for the different drawer positions. */ -@objc public protocol PulleyDrawerViewControllerDelegate: PulleyDelegate { +public protocol PulleyDrawerViewControllerDelegate: PulleyDelegate { func collapsedDrawerHeight() -> CGFloat func partialRevealDrawerHeight() -> CGFloat + func supportedDrawerPositions() -> [PulleyPosition] } /** * View controllers that are the main content can implement this to receive changes in state. */ -@objc public protocol PulleyPrimaryContentControllerDelegate: PulleyDelegate { +public protocol PulleyPrimaryContentControllerDelegate: PulleyDelegate { // Not currently used for anything, but it's here for parity with the hopes that it'll one day be used. } @@ -42,11 +43,17 @@ import UIKit - partiallyRevealed: When the drawer is partially revealed. - open: When the drawer is fully open. */ -public enum PulleyPosition { +public enum PulleyPosition: Int { - case collapsed - case partiallyRevealed - case open + case collapsed = 0 + case partiallyRevealed = 1 + case open = 2 + + static var all: [PulleyPosition] = [ + .collapsed, + .partiallyRevealed, + .open + ] } private let kPulleyDefaultCollapsedHeight: CGFloat = 68.0 @@ -72,7 +79,7 @@ open class PulleyViewController: UIViewController, UIScrollViewDelegate, PulleyP private var dimmingViewTapRecognizer: UITapGestureRecognizer? /// The current content view controller (shown behind the drawer). - private(set) var primaryContentViewController: UIViewController! { + fileprivate(set) var primaryContentViewController: UIViewController! { willSet { guard let controller = primaryContentViewController else { @@ -102,7 +109,7 @@ open class PulleyViewController: UIViewController, UIScrollViewDelegate, PulleyP } /// The current drawer view controller (shown in the drawer). - private(set) var drawerContentViewController: UIViewController! { + fileprivate(set) var drawerContentViewController: UIViewController! { willSet { guard let controller = drawerContentViewController else { @@ -124,6 +131,8 @@ open class PulleyViewController: UIViewController, UIScrollViewDelegate, PulleyP self.drawerContentContainer.addSubview(controller.view) self.addChildViewController(controller) + self.setNeedsSupportedDrawerPositionsUpdate() + if self.isViewLoaded { self.view.setNeedsLayout() @@ -135,7 +144,7 @@ open class PulleyViewController: UIViewController, UIScrollViewDelegate, PulleyP public weak var delegate: PulleyDelegate? /// The current position of the drawer. - public private(set) var drawerPosition: PulleyPosition = .collapsed { + public fileprivate(set) var drawerPosition: PulleyPosition = .collapsed { didSet { setNeedsStatusBarAppearanceUpdate() } @@ -219,6 +228,38 @@ open class PulleyViewController: UIViewController, UIScrollViewDelegate, PulleyP } } + /// The drawer positions supported by the drawer + fileprivate var supportedDrawerPositions: [PulleyPosition] = PulleyPosition.all { + didSet { + + guard self.isViewLoaded else { + return + } + + guard supportedDrawerPositions.count > 0 else { + supportedDrawerPositions = PulleyPosition.all + return + } + + self.view.setNeedsLayout() + + if supportedDrawerPositions.contains(drawerPosition) + { + setDrawerPosition(position: drawerPosition) + } + else + { + let lowestDrawerState: PulleyPosition = supportedDrawerPositions.min { (pos1, pos2) -> Bool in + return pos1.rawValue < pos2.rawValue + } ?? .collapsed + + setDrawerPosition(position: lowestDrawerState, animated: false) + } + + drawerScrollView.isScrollEnabled = supportedDrawerPositions.count > 1 + } + } + /** Initialize the drawer controller programmtically. @@ -341,6 +382,12 @@ open class PulleyViewController: UIViewController, UIScrollViewDelegate, PulleyP scrollViewDidScroll(drawerScrollView) } + override open func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + setNeedsSupportedDrawerPositionsUpdate() + } + override open func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() @@ -348,8 +395,6 @@ open class PulleyViewController: UIViewController, UIScrollViewDelegate, PulleyP primaryContentContainer.frame = self.view.bounds backgroundDimmingView.frame = self.view.bounds - // Layout scrollview - drawerScrollView.frame = CGRect(x: 0, y: topInset, width: self.view.bounds.width, height: self.view.bounds.height - topInset) // Layout container var collapsedHeight:CGFloat = kPulleyDefaultCollapsedHeight @@ -363,6 +408,19 @@ open class PulleyViewController: UIViewController, UIScrollViewDelegate, PulleyP let lowestStop = [(self.view.bounds.size.height - topInset), collapsedHeight, partialRevealHeight].min() ?? 0 let bounceOverflowMargin: CGFloat = 20.0 + + if supportedDrawerPositions.contains(.open) + { + // Layout scrollview + drawerScrollView.frame = CGRect(x: 0, y: topInset, width: self.view.bounds.width, height: self.view.bounds.height - topInset) + } + else + { + // Layout scrollview + let adjustedTopInset: CGFloat = supportedDrawerPositions.contains(.partiallyRevealed) ? partialRevealHeight : collapsedHeight + drawerScrollView.frame = CGRect(x: 0, y: self.view.bounds.height - adjustedTopInset, width: self.view.bounds.width, height: adjustedTopInset) + } + drawerContentContainer.frame = CGRect(x: 0, y: drawerScrollView.bounds.height - lowestStop, width: drawerScrollView.bounds.width, height: drawerScrollView.bounds.height + bounceOverflowMargin) drawerBackgroundVisualEffectView?.frame = drawerContentContainer.frame drawerShadowView.frame = drawerContentContainer.frame @@ -399,6 +457,10 @@ open class PulleyViewController: UIViewController, UIScrollViewDelegate, PulleyP */ public func setDrawerPosition(position: PulleyPosition, animated: Bool = true) { + guard supportedDrawerPositions.contains(position) else { + return + } + drawerPosition = position var collapsedHeight:CGFloat = kPulleyDefaultCollapsedHeight @@ -500,6 +562,21 @@ open class PulleyViewController: UIViewController, UIScrollViewDelegate, PulleyP } } + /** + Update the supported drawer positions allows by the Pulley Drawer + */ + public func setNeedsSupportedDrawerPositionsUpdate() + { + if let drawerVCCompliant = drawerContentViewController as? PulleyDrawerViewControllerDelegate + { + supportedDrawerPositions = drawerVCCompliant.supportedDrawerPositions() + } + else + { + supportedDrawerPositions = PulleyPosition.all + } + } + // MARK: Actions func dimmingViewTapRecognizerAction(gestureRecognizer: UITapGestureRecognizer) @@ -531,7 +608,23 @@ open class PulleyViewController: UIViewController, UIScrollViewDelegate, PulleyP partialRevealHeight = drawerVCCompliant.partialRevealDrawerHeight() } - let drawerStops = [(self.view.bounds.size.height - topInset), collapsedHeight, partialRevealHeight] + var drawerStops: [CGFloat] = [CGFloat]() + + if supportedDrawerPositions.contains(.open) + { + drawerStops.append((self.view.bounds.size.height - topInset)) + } + + if supportedDrawerPositions.contains(.partiallyRevealed) + { + drawerStops.append(partialRevealHeight) + } + + if supportedDrawerPositions.contains(.collapsed) + { + drawerStops.append(collapsedHeight) + } + let lowestStop = drawerStops.min() ?? 0 let distanceFromBottomOfView = lowestStop + lastDragTargetContentOffset.y @@ -546,13 +639,13 @@ open class PulleyViewController: UIViewController, UIScrollViewDelegate, PulleyP } } - if abs(Float(currentClosestStop - (self.view.bounds.size.height - topInset))) <= FLT_EPSILON + if abs(Float(currentClosestStop - (self.view.bounds.size.height - topInset))) <= FLT_EPSILON && supportedDrawerPositions.contains(.open) { setDrawerPosition(position: .open, animated: true) - } else if abs(Float(currentClosestStop - collapsedHeight)) <= FLT_EPSILON + } else if abs(Float(currentClosestStop - collapsedHeight)) <= FLT_EPSILON && supportedDrawerPositions.contains(.collapsed) { setDrawerPosition(position: .collapsed, animated: true) - } else { + } else if supportedDrawerPositions.contains(.partiallyRevealed){ setDrawerPosition(position: .partiallyRevealed, animated: true) } } @@ -582,7 +675,23 @@ open class PulleyViewController: UIViewController, UIScrollViewDelegate, PulleyP partialRevealHeight = drawerVCCompliant.partialRevealDrawerHeight() } - let drawerStops = [(self.view.bounds.size.height - topInset), collapsedHeight, partialRevealHeight] + var drawerStops: [CGFloat] = [CGFloat]() + + if supportedDrawerPositions.contains(.open) || true + { + drawerStops.append((self.view.bounds.size.height - topInset)) + } + + if supportedDrawerPositions.contains(.partiallyRevealed) || true + { + drawerStops.append(partialRevealHeight) + } + + if supportedDrawerPositions.contains(.collapsed) || true + { + drawerStops.append(collapsedHeight) + } + let lowestStop = drawerStops.min() ?? 0 if scrollView.contentOffset.y > partialRevealHeight - lowestStop From 62254c325e49979c2c9a35bf6a4c07f5b11c9fa1 Mon Sep 17 00:00:00 2001 From: Brendan Lee Date: Tue, 20 Sep 2016 22:15:43 -0400 Subject: [PATCH 2/4] Add doc update for the ability to disable drawer states. --- README.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index a49ab89..adc8ae3 100644 --- a/README.md +++ b/README.md @@ -90,12 +90,13 @@ if let drawer = self.parentViewController as? PulleyViewController 1. See the 3 protocols above. 2. You can adjust the inset from the top of the screen in the "Open" state by setting the -topInset property on the `PulleyViewController`. -3. You can adjust the corner radius applied to the drawer by setting the -drawerCornerRadius property on the `PulleyViewController`. -4. You can adjust the shadow opacity applied to the drawer by setting the -shadowOpacity property on the `PulleyViewController`. -5. You can adjust the shadow radius applied to the drawer by setting the -shadowRadius property on the `PulleyViewController`. -6. You can adjust the background dimming color by setting the -backgroundDimmingColor to an opaque color on the `PulleyViewController`. -7. You can adjust / remove the background blur effect by setting the -drawerBackgroundVisualEffectView property on the `PulleyViewController`. -8. You can adjust the alpha of the background dimming color by setting the -backgroundDimmingOpacity property on the `PulleyViewController`. -9. You can change the drawer position by calling setDrawerPosition( : ) on the `PulleyViewController`. -10. If an object needs to receive delegate callbacks and _isn't_ one of the view controller's presented then you can use the -delegate property on the `PulleyViewController`. -11. The Swift Interface for `PulleyViewController` is documented in case you want to see real documentation instead of a numbered list of useful things. +3. You can enable / disable drawer positions by implementing `PulleyDrawerViewControllerDelegate` in your 'drawer' view controller. If you need to change it, call `setNeedsSupportedDrawerPositionsUpdate()` on the `PulleyViewController` so it will recalculate the drawer based on your new settings. +4. You can adjust the corner radius applied to the drawer by setting the -drawerCornerRadius property on the `PulleyViewController`. +5. You can adjust the shadow opacity applied to the drawer by setting the -shadowOpacity property on the `PulleyViewController`. +6. You can adjust the shadow radius applied to the drawer by setting the -shadowRadius property on the `PulleyViewController`. +7. You can adjust the background dimming color by setting the -backgroundDimmingColor to an opaque color on the `PulleyViewController`. +8. You can adjust / remove the background blur effect by setting the -drawerBackgroundVisualEffectView property on the `PulleyViewController`. +9. You can adjust the alpha of the background dimming color by setting the -backgroundDimmingOpacity property on the `PulleyViewController`. +10. You can change the drawer position by calling setDrawerPosition( : ) on the `PulleyViewController`. +11. If an object needs to receive delegate callbacks and _isn't_ one of the view controller's presented then you can use the -delegate property on the `PulleyViewController`. +12. The Swift Interface for `PulleyViewController` is documented in case you want to see real documentation instead of a numbered list of useful things. From 1fe9d482292daa8a9a212be44d7b76cdb14a105b Mon Sep 17 00:00:00 2001 From: Brendan Lee Date: Thu, 22 Sep 2016 22:19:15 -0400 Subject: [PATCH 3/4] Make primaryContentViewController and drawerContentViewController getters public. --- PulleyLib/PulleyViewController.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PulleyLib/PulleyViewController.swift b/PulleyLib/PulleyViewController.swift index 19b3400..e9743aa 100644 --- a/PulleyLib/PulleyViewController.swift +++ b/PulleyLib/PulleyViewController.swift @@ -79,7 +79,7 @@ open class PulleyViewController: UIViewController, UIScrollViewDelegate, PulleyP private var dimmingViewTapRecognizer: UITapGestureRecognizer? /// The current content view controller (shown behind the drawer). - fileprivate(set) var primaryContentViewController: UIViewController! { + public fileprivate(set) var primaryContentViewController: UIViewController! { willSet { guard let controller = primaryContentViewController else { @@ -109,7 +109,7 @@ open class PulleyViewController: UIViewController, UIScrollViewDelegate, PulleyP } /// The current drawer view controller (shown in the drawer). - fileprivate(set) var drawerContentViewController: UIViewController! { + public fileprivate(set) var drawerContentViewController: UIViewController! { willSet { guard let controller = drawerContentViewController else { From d8a6cdc30ce10580eba12091bba58e1b6b908328 Mon Sep 17 00:00:00 2001 From: Brendan Lee Date: Mon, 26 Sep 2016 23:40:34 -0400 Subject: [PATCH 4/4] Update supported drawer positions when setting a new primary VC or when setting a new drawer VC --- PulleyLib/PulleyViewController.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PulleyLib/PulleyViewController.swift b/PulleyLib/PulleyViewController.swift index e9743aa..34df883 100644 --- a/PulleyLib/PulleyViewController.swift +++ b/PulleyLib/PulleyViewController.swift @@ -104,6 +104,7 @@ open class PulleyViewController: UIViewController, UIScrollViewDelegate, PulleyP if self.isViewLoaded { self.view.setNeedsLayout() + self.setNeedsSupportedDrawerPositionsUpdate() } } } @@ -131,11 +132,10 @@ open class PulleyViewController: UIViewController, UIScrollViewDelegate, PulleyP self.drawerContentContainer.addSubview(controller.view) self.addChildViewController(controller) - self.setNeedsSupportedDrawerPositionsUpdate() - if self.isViewLoaded { self.view.setNeedsLayout() + self.setNeedsSupportedDrawerPositionsUpdate() } } }