diff --git a/Pulley.podspec b/Pulley.podspec
index cd4b92a..ce57a82 100644
--- a/Pulley.podspec
+++ b/Pulley.podspec
@@ -8,7 +8,7 @@
Pod::Spec.new do |s|
s.name = 'Pulley'
- s.version = ENV['LIB_VERSION'] || '2.8.5'
+ s.version = ENV['LIB_VERSION'] || '2.9.0'
s.summary = 'A library to imitate the iOS 10 Maps UI.'
# This description is used to generate tags and improve search results.
diff --git a/Pulley/DrawerContentViewController.swift b/Pulley/DrawerContentViewController.swift
index a001ce2..2604071 100755
--- a/Pulley/DrawerContentViewController.swift
+++ b/Pulley/DrawerContentViewController.swift
@@ -142,7 +142,7 @@ extension DrawerContentViewController: PulleyDrawerViewControllerDelegate {
func drawerDisplayModeDidChange(drawer: PulleyViewController) {
print("Drawer: \(drawer.currentDisplayMode)")
- gripperTopConstraint.isActive = drawer.currentDisplayMode == .drawer
+ gripperTopConstraint.isActive = (drawer.currentDisplayMode == .drawer || drawer.currentDisplayMode == .compact)
}
}
diff --git a/Pulley/Main.storyboard b/Pulley/Main.storyboard
index 2aa327c..c2fc0d1 100644
--- a/Pulley/Main.storyboard
+++ b/Pulley/Main.storyboard
@@ -311,8 +311,145 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Pulley/PrimaryTransitionTargetViewController.swift b/Pulley/PrimaryTransitionTargetViewController.swift
index 832d918..332dc92 100644
--- a/Pulley/PrimaryTransitionTargetViewController.swift
+++ b/Pulley/PrimaryTransitionTargetViewController.swift
@@ -12,8 +12,17 @@ import Pulley
class PrimaryTransitionTargetViewController: UIViewController {
@IBAction func goBackButtonPressed(sender: AnyObject) {
+ // Uncomment the bellow code to create a secondary drawer content view controller
+ // and set it's initial position with setDrawerContentViewController(controller, position, animated, completion)
+ /*
+ let drawerContent = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SecondaryDrawerContentViewController")
+
+ self.pulleyViewController?.setDrawerContentViewController(controller: drawerContent, position: .open, animated: true, completion: nil)
+ */
+
let primaryContent = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PrimaryContentViewController")
self.pulleyViewController?.setPrimaryContentViewController(controller: primaryContent, animated: true)
+
}
}
diff --git a/PulleyLib/PulleyViewController.swift b/PulleyLib/PulleyViewController.swift
index c0e48ee..1b46995 100644
--- a/PulleyLib/PulleyViewController.swift
+++ b/PulleyLib/PulleyViewController.swift
@@ -90,6 +90,12 @@ public typealias PulleyAnimationCompletionBlock = ((_ finished: Bool) -> Void)
.closed
]
+ public static let compact: [PulleyPosition] = [
+ .collapsed,
+ .open,
+ .closed
+ ]
+
public let rawValue: Int
public init(rawValue: Int) {
@@ -160,10 +166,12 @@ public typealias PulleyAnimationCompletionBlock = ((_ finished: Bool) -> Void)
///
/// - panel: Show as a floating panel (replaces: leftSide)
/// - drawer: Show as a bottom drawer (replaces: bottomDrawer)
+/// - compact: Show as a compacted bottom drawer (support for iPhone SE size class)
/// - automatic: Determine it based on device / orientation / size class (like Maps.app)
public enum PulleyDisplayMode {
case panel
case drawer
+ case compact
case automatic
}
@@ -181,6 +189,14 @@ public enum PulleyPanelCornerPlacement {
case bottomRight
}
+/// Represents the positioning of the drawer when the `displayMode` is set to either `PulleyDisplayMode.panel` or `PulleyDisplayMode.automatic`.
+/// - bottomLeft: The drawer will placed in the bottom left corner
+/// - bottomRight: The drawer will placed in the bottom right corner
+public enum PulleyCompactCornerPlacement {
+ case bottomLeft
+ case bottomRight
+}
+
/// Represents the 'snap' mode for Pulley. The default is 'nearest position'. You can use 'nearestPositionUnlessExceeded' to make the drawer feel lighter or heavier.
///
/// - nearestPosition: Snap to the nearest position when scroll stops
@@ -370,6 +386,26 @@ open class PulleyViewController: UIViewController, PulleyDrawerViewControllerDel
}
}
+ /// Depending on what corner placement is being used, different values from this struct will apply. For example, 'bottomRight' corner placement will utilize the .top, .right, and .bottom inset properties and it will ignore the .left property (use compactWidth property to specify width)
+ @IBInspectable public var compactInsets: UIEdgeInsets = UIEdgeInsets(top: 8.0, left: 8.0, bottom: 10.0, right: 8.0) {
+ didSet {
+ if oldValue != compactInsets, self.isViewLoaded
+ {
+ self.view.setNeedsLayout()
+ }
+ }
+ }
+
+ /// The width of the drawer in compact displayMode
+ @IBInspectable public var compactWidth: CGFloat = 292.0 {
+ didSet {
+ if oldValue != compactWidth, self.isViewLoaded
+ {
+ self.view.setNeedsLayout()
+ }
+ }
+ }
+
/// The corner radius for the drawer.
/// Note: This property is ignored if your drawerContentViewController's view.layer.mask has a custom mask applied using a CAShapeLayer.
/// Note: Custom CAShapeLayer as your drawerContentViewController's view.layer mask will override Pulley's internal corner rounding and use that mask as the drawer mask.
@@ -482,7 +518,7 @@ open class PulleyViewController: UIViewController, PulleyDrawerViewControllerDel
}
}
- /// The Y positioning for Pulley. This property is only oberserved when `displayMode` is set to `.automatic` or `bottom`. Default value is `.topLeft`.
+ /// The Y positioning for Pulley. This property is only oberserved when `displayMode` is set to `.automatic` or `.pannel`. Default value is `.topLeft`.
public var panelCornerPlacement: PulleyPanelCornerPlacement = .topLeft {
didSet {
if self.isViewLoaded
@@ -491,6 +527,17 @@ open class PulleyViewController: UIViewController, PulleyDrawerViewControllerDel
}
}
}
+
+ /// The Y positioning for Pulley. This property is only oberserved when `displayMode` is set to `.automatic` or `.compact`. Default value is `.bottomLeft`.
+ public var compactCornerPlacement: PulleyCompactCornerPlacement = .bottomLeft {
+ didSet {
+ if self.isViewLoaded
+ {
+ self.view.setNeedsLayout()
+ }
+ }
+ }
+
/// This is here exclusively to support IBInspectable in Interface Builder because Interface Builder can't deal with enums. If you're doing this in code use the -initialDrawerPosition property instead. Available strings are: open, closed, partiallyRevealed, collapsed
@IBInspectable public var initialDrawerPositionFromIB: String? {
@@ -600,7 +647,7 @@ open class PulleyViewController: UIViewController, PulleyDrawerViewControllerDel
}
guard supportedPositions.count > 0 else {
- supportedPositions = PulleyPosition.all
+ supportedPositions = self.currentDisplayMode == .compact ? PulleyPosition.compact : PulleyPosition.all
return
}
@@ -612,6 +659,10 @@ open class PulleyViewController: UIViewController, PulleyDrawerViewControllerDel
{
setDrawerPosition(position: drawerPosition, animated: false)
}
+ else if (self.currentDisplayMode == .compact && drawerPosition == .partiallyRevealed && supportedPositions.contains(.open))
+ {
+ setDrawerPosition(position: .open, animated: false)
+ }
else
{
let lowestDrawerState: PulleyPosition = supportedPositions.filter({ $0 != .closed }).min { (pos1, pos2) -> Bool in
@@ -634,6 +685,7 @@ open class PulleyViewController: UIViewController, PulleyDrawerViewControllerDel
if self.isViewLoaded
{
self.view.setNeedsLayout()
+ self.setNeedsSupportedDrawerPositionsUpdate()
}
delegate?.drawerDisplayModeDidChange?(drawer: self)
@@ -648,7 +700,7 @@ open class PulleyViewController: UIViewController, PulleyDrawerViewControllerDel
fileprivate var isChangingDrawerPosition: Bool = false
/// The height of the open position for the drawer
- private var heightOfOpenDrawer: CGFloat {
+ public var heightOfOpenDrawer: CGFloat {
let safeAreaTopInset = pulleySafeAreaInsets.top
let safeAreaBottomInset = pulleySafeAreaInsets.bottom
@@ -841,9 +893,18 @@ open class PulleyViewController: UIViewController, PulleyDrawerViewControllerDel
let safeAreaBottomInset = pulleySafeAreaInsets.bottom
let safeAreaLeftInset = pulleySafeAreaInsets.left
let safeAreaRightInset = pulleySafeAreaInsets.right
-
- let displayModeForCurrentLayout: PulleyDisplayMode = displayMode != .automatic ? displayMode : ((self.view.bounds.width >= 600.0 || self.traitCollection.horizontalSizeClass == .regular) ? .panel : .drawer)
+ var automaticDisplayMode: PulleyDisplayMode = .drawer
+ if (self.view.bounds.width >= 600.0 ) {
+ switch self.traitCollection.horizontalSizeClass {
+ case .compact:
+ automaticDisplayMode = .compact
+ default:
+ automaticDisplayMode = .panel
+ }
+ }
+
+ let displayModeForCurrentLayout: PulleyDisplayMode = displayMode != .automatic ? displayMode : automaticDisplayMode
currentDisplayMode = displayModeForCurrentLayout
@@ -928,35 +989,61 @@ open class PulleyViewController: UIViewController, PulleyDrawerViewControllerDel
partialRevealHeight = drawerVCCompliant.partialRevealDrawerHeight?(bottomSafeArea: safeAreaBottomInset) ?? kPulleyDefaultPartialRevealHeight
}
- let lowestStop = [(self.view.bounds.size.height - panelInsets.bottom - safeAreaTopInset), collapsedHeight, partialRevealHeight].min() ?? 0
-
- let xOrigin = (panelCornerPlacement == .bottomLeft || panelCornerPlacement == .topLeft) ? (safeAreaLeftInset + panelInsets.left) : (self.view.bounds.maxX - (safeAreaRightInset + panelInsets.right) - panelWidth)
+ var lowestStop: CGFloat = 0
+ var xOrigin: CGFloat = 0
+ var yOrigin: CGFloat = 0
+ let width = displayModeForCurrentLayout == .compact ? compactWidth : panelWidth
- let yOrigin = (panelCornerPlacement == .bottomLeft || panelCornerPlacement == .bottomRight) ? (panelInsets.top + safeAreaTopInset) : (panelInsets.top + safeAreaTopInset + bounceOverflowMargin)
+ if (displayModeForCurrentLayout == .compact)
+ {
+ lowestStop = [(self.view.bounds.size.height - compactInsets.bottom - safeAreaTopInset), collapsedHeight, partialRevealHeight].min() ?? 0
+ xOrigin = (compactCornerPlacement == .bottomLeft) ? (safeAreaLeftInset + compactInsets.left) : (self.view.bounds.maxX - (safeAreaRightInset + compactInsets.right) - compactWidth)
+
+ yOrigin = (compactInsets.top + safeAreaTopInset)
+ }
+ else
+ {
+ lowestStop = [(self.view.bounds.size.height - panelInsets.bottom - safeAreaTopInset), collapsedHeight, partialRevealHeight].min() ?? 0
+ xOrigin = (panelCornerPlacement == .bottomLeft || panelCornerPlacement == .topLeft) ? (safeAreaLeftInset + panelInsets.left) : (self.view.bounds.maxX - (safeAreaRightInset + panelInsets.right) - panelWidth)
+
+ yOrigin = (panelCornerPlacement == .bottomLeft || panelCornerPlacement == .bottomRight) ? (panelInsets.top + safeAreaTopInset) : (panelInsets.top + safeAreaTopInset + bounceOverflowMargin)
+
+ }
if supportedPositions.contains(.open)
{
// Layout scrollview
- drawerScrollView.frame = CGRect(x: xOrigin, y: yOrigin, width: panelWidth, height: heightOfOpenDrawer)
+ drawerScrollView.frame = CGRect(x: xOrigin, y: yOrigin, width: width, height: heightOfOpenDrawer)
}
else
{
// Layout scrollview
let adjustedTopInset: CGFloat = supportedPositions.contains(.partiallyRevealed) ? partialRevealHeight : collapsedHeight
- drawerScrollView.frame = CGRect(x: xOrigin, y: yOrigin, width: panelWidth, height: adjustedTopInset)
+ drawerScrollView.frame = CGRect(x: xOrigin, y: yOrigin, width: width, height: adjustedTopInset)
}
syncDrawerContentViewSizeToMatchScrollPositionForSideDisplayMode()
drawerScrollView.contentSize = CGSize(width: drawerScrollView.bounds.width, height: self.view.bounds.height + (self.view.bounds.height - lowestStop))
- switch panelCornerPlacement {
- case .topLeft, .topRight:
- drawerScrollView.transform = CGAffineTransform(scaleX: 1.0, y: -1.0)
- case .bottomLeft, .bottomRight:
- drawerScrollView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
+ if (displayModeForCurrentLayout == .compact)
+ {
+ switch compactCornerPlacement {
+ case .bottomLeft, .bottomRight:
+ drawerScrollView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
+ }
}
-
+ else
+ {
+ switch panelCornerPlacement {
+ case .topLeft, .topRight:
+ drawerScrollView.transform = CGAffineTransform(scaleX: 1.0, y: -1.0)
+ case .bottomLeft, .bottomRight:
+ drawerScrollView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
+ }
+
+ }
+
backgroundDimmingView.isHidden = true
}
@@ -1181,7 +1268,7 @@ open class PulleyViewController: UIViewController, PulleyDrawerViewControllerDel
private func syncDrawerContentViewSizeToMatchScrollPositionForSideDisplayMode() {
- guard currentDisplayMode == .panel else {
+ guard currentDisplayMode == .panel || currentDisplayMode == .compact else {
return
}
@@ -1360,10 +1447,11 @@ open class PulleyViewController: UIViewController, PulleyDrawerViewControllerDel
Change the current drawer content view controller (The one inside the drawer)
- parameter controller: The controller to replace it with
+ - parameter position: The initial position of the contoller
- parameter animated: Whether or not to animate the change.
- parameter completion: A block object to be executed when the animation sequence ends. The Bool indicates whether or not the animations actually finished before the completion handler was called.
*/
- public func setDrawerContentViewController(controller: UIViewController, animated: Bool = true, completion: PulleyAnimationCompletionBlock?)
+ public func setDrawerContentViewController(controller: UIViewController, position: PulleyPosition? = nil, animated: Bool = true, completion: PulleyAnimationCompletionBlock?)
{
// Account for transition issue in iOS 11
controller.view.frame = drawerContentContainer.bounds
@@ -1374,22 +1462,34 @@ open class PulleyViewController: UIViewController, PulleyDrawerViewControllerDel
UIView.transition(with: drawerContentContainer, duration: 0.5, options: .transitionCrossDissolve, animations: { [weak self] () -> Void in
self?.drawerContentViewController = controller
- self?.setDrawerPosition(position: self?.drawerPosition ?? .collapsed, animated: false)
-
- }, completion: { (completed) in
-
- completion?(completed)
+ self?.setDrawerPosition(position: position ?? (self?.drawerPosition ?? .collapsed), animated: false)
+ }, completion: { (completed) in
+ completion?(completed)
})
}
else
{
drawerContentViewController = controller
- setDrawerPosition(position: drawerPosition, animated: false)
+ setDrawerPosition(position: position ?? drawerPosition, animated: false)
completion?(true)
}
}
+ /**
+ Change the current drawer content view controller (The one inside the drawer). This method exists for backwards compatibility.
+
+ - parameter controller: The controller to replace it with
+ - parameter animated: Whether or not to animate the change.
+ - parameter completion: A block object to be executed when the animation sequence ends. The Bool indicates whether or not the animations actually finished before the completion handler was called.
+ */
+
+ public func setDrawerContentViewController(controller: UIViewController, animated: Bool = true, completion: PulleyAnimationCompletionBlock?)
+ {
+ setDrawerContentViewController(controller: controller, position: nil, animated: animated, completion: completion)
+
+ }
+
/**
Change the current drawer content view controller (The one inside the drawer). This method exists for backwards compatibility.
@@ -1398,7 +1498,7 @@ open class PulleyViewController: UIViewController, PulleyDrawerViewControllerDel
*/
public func setDrawerContentViewController(controller: UIViewController, animated: Bool = true)
{
- setDrawerContentViewController(controller: controller, animated: animated, completion: nil)
+ setDrawerContentViewController(controller: controller, position: nil, animated: animated, completion: nil)
}
/**
@@ -1408,11 +1508,15 @@ open class PulleyViewController: UIViewController, PulleyDrawerViewControllerDel
{
if let drawerVCCompliant = drawerContentViewController as? PulleyDrawerViewControllerDelegate
{
- supportedPositions = drawerVCCompliant.supportedDrawerPositions?() ?? PulleyPosition.all
+ if let setSupportedDrawerPositions = drawerVCCompliant.supportedDrawerPositions?() {
+ supportedPositions = self.currentDisplayMode == .compact ? setSupportedDrawerPositions.filter(PulleyPosition.compact.contains) : setSupportedDrawerPositions
+ } else {
+ supportedPositions = self.currentDisplayMode == .compact ? PulleyPosition.compact : PulleyPosition.all
+ }
}
else
{
- supportedPositions = PulleyPosition.all
+ supportedPositions = self.currentDisplayMode == .compact ? PulleyPosition.compact : PulleyPosition.all
}
}
@@ -1492,9 +1596,9 @@ open class PulleyViewController: UIViewController, PulleyDrawerViewControllerDel
open func supportedDrawerPositions() -> [PulleyPosition] {
if let drawerVCCompliant = drawerContentViewController as? PulleyDrawerViewControllerDelegate,
let supportedPositions = drawerVCCompliant.supportedDrawerPositions?() {
- return supportedPositions
+ return (self.currentDisplayMode == .compact ? supportedPositions.filter(PulleyPosition.compact.contains) : supportedPositions)
} else {
- return PulleyPosition.all
+ return (self.currentDisplayMode == .compact ? PulleyPosition.compact : PulleyPosition.all)
}
}
diff --git a/README.md b/README.md
index fdef7e3..55a4387 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,10 @@ A library to imitate the drawer in Maps for iOS 10/11. The master branch follows
### Update / Migration Info
-**ATTENTION:**
+**ATTENTION:**
+Pulley 2.9.0 has new properties to support a new displayMode. The base functionality should work without any significant changes. The biggest change being the new displayMode of `.compact` to replicate Apple Maps Behavior on the iPhone SE size class devices. This is an exact replica of the behavior of the Apple Maps drawer, therefor when the `currentDisplayMode` of the `PulleyViewController` is `.compact` then the only `supportedDrawerPositions` for the view controller when in `.compact` mode are `.open`, `.closed`, and `.collapsed`. This mode also has new @IBInspectable properties, `compactInsets` and `compactWidth`. This mode behaves in a very similar way to `.panel` mode. See the pull request [here](https://github.com/52inc/Pulley/pull/347) for the motivation behind this feature. Also in this release, `setDrawerContentViewController(controller: UIViewController, position: PulleyPosition? = nil, animated: Bool = true, completion: PulleyAnimationCompletionBlock?)` has a new optional parameter `position` to set a new drawer position the drawer when a new `DrawerContentViewController` is set. See [this](https://github.com/52inc/Pulley/pull/349) pull request for the motivation behind this feature.
+
+
Pulley 2.5.0 had significant renaming changes to support new features. Although property names have changed, the functionality should work without any significant changes (aside from renaming). See [this thread](https://github.com/52inc/Pulley/issues/252) for additional information.