Skip to content

Commit

Permalink
Swift 3 support
Browse files Browse the repository at this point in the history
  • Loading branch information
tristanhimmelman committed Sep 14, 2016
1 parent 5f8d080 commit 0268999
Show file tree
Hide file tree
Showing 11 changed files with 189 additions and 175 deletions.
158 changes: 78 additions & 80 deletions HidingNavigationBar/HidingNavigationBarManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
import UIKit

public protocol HidingNavigationBarManagerDelegate: class {
func hidingNavigationBarManagerDidUpdateScrollViewInsets(manager: HidingNavigationBarManager)
func hidingNavigationBarManagerDidChangeState(manager: HidingNavigationBarManager, toState state: HidingNavigationBarState)
func hidingNavigationBarManagerDidUpdateScrollViewInsets(_ manager: HidingNavigationBarManager)
func hidingNavigationBarManagerDidChangeState(_ manager: HidingNavigationBarManager, toState state: HidingNavigationBarState)
}

public enum HidingNavigationBarState: String {
Expand All @@ -21,12 +21,12 @@ public enum HidingNavigationBarState: String {
}

public enum HidingNavigationForegroundAction {
case Default
case Show
case Hide
case `default`
case show
case hide
}

public class HidingNavigationBarManager: NSObject, UIScrollViewDelegate, UIGestureRecognizerDelegate {
open class HidingNavigationBarManager: NSObject, UIScrollViewDelegate, UIGestureRecognizerDelegate {
// The view controller that is part of the navigation stack
unowned var viewController: UIViewController

Expand All @@ -37,29 +37,29 @@ public class HidingNavigationBarManager: NSObject, UIScrollViewDelegate, UIGestu
weak var extensionView: UIView?

// Control the resistance when scrolling up/down before the navbar expands/contracts again.
public var expansionResistance: CGFloat = 0
public var contractionResistance: CGFloat = 0
open var expansionResistance: CGFloat = 0
open var contractionResistance: CGFloat = 0

weak public var delegate: HidingNavigationBarManagerDelegate?
weak open var delegate: HidingNavigationBarManagerDelegate?

public var refreshControl: UIRefreshControl?
open var refreshControl: UIRefreshControl?

private var navBarController: HidingViewController
private var extensionController: HidingViewController
private var tabBarController: HidingViewController?
fileprivate var navBarController: HidingViewController
fileprivate var extensionController: HidingViewController
fileprivate var tabBarController: HidingViewController?

// Scroll calculation values
private var topInset: CGFloat = 0
private var previousYOffset = CGFloat.NaN
private var resistanceConsumed: CGFloat = 0
private var isUpdatingValues = false
fileprivate var topInset: CGFloat = 0
fileprivate var previousYOffset = CGFloat.nan
fileprivate var resistanceConsumed: CGFloat = 0
fileprivate var isUpdatingValues = false

// Hiding navigation bar state
private var currentState = HidingNavigationBarState.Open
private var previousState = HidingNavigationBarState.Open
fileprivate var currentState = HidingNavigationBarState.Open
fileprivate var previousState = HidingNavigationBarState.Open

//Options
public var onForegroundAction = HidingNavigationForegroundAction.Default
open var onForegroundAction = HidingNavigationForegroundAction.default

public init(viewController: UIViewController, scrollView: UIScrollView){
if viewController.navigationController == nil || viewController.navigationController?.navigationBar == nil {
Expand All @@ -80,8 +80,6 @@ public class HidingNavigationBarManager: NSObject, UIScrollViewDelegate, UIGestu
navBarController.child = extensionController
navBarController.alphaFadeEnabled = true

viewController.tabBarController?.tabBar

super.init()

// track panning on scroll view
Expand All @@ -90,67 +88,67 @@ public class HidingNavigationBarManager: NSObject, UIScrollViewDelegate, UIGestu
scrollView.addGestureRecognizer(panGesture)

navBarController.expandedCenter = {[weak self] (view: UIView) -> CGPoint in
return CGPointMake(CGRectGetMidX(view.bounds), CGRectGetMidY(view.bounds) + (self?.statusBarHeight() ?? 0))
return CGPoint(x: view.bounds.midX, y: view.bounds.midY + (self?.statusBarHeight() ?? 0))
}

extensionController.expandedCenter = {[weak self] (view: UIView) -> CGPoint in
let topOffset = (self?.navBarController.contractionAmountValue() ?? 0) + (self?.statusBarHeight() ?? 0)
let point = CGPointMake(CGRectGetMidX(view.bounds), CGRectGetMidY(view.bounds) + topOffset)
let point = CGPoint(x: view.bounds.midX, y: view.bounds.midY + topOffset)

return point
}

updateContentInsets()

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(HidingNavigationBarManager.applicationWillEnterForeground), name: UIApplicationDidBecomeActiveNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(HidingNavigationBarManager.applicationWillEnterForeground), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil)
}

deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
NotificationCenter.default.removeObserver(self)
}

//MARK: Public methods

public func manageBottomBar(view: UIView){
open func manageBottomBar(_ view: UIView){
tabBarController = HidingViewController(view: view)
tabBarController?.contractsUpwards = false
tabBarController?.expandedCenter = {[weak self] (view: UIView) -> CGPoint in
let height = self?.viewController.view.frame.size.height ?? 0
let point = CGPointMake(CGRectGetMidX(view.bounds), height - CGRectGetMidY(view.bounds))
let point = CGPoint(x: view.bounds.midX, y: height - view.bounds.midY)

return point
}
}

public func addExtensionView(view: UIView) {
open func addExtensionView(_ view: UIView) {
extensionView?.removeFromSuperview()
extensionView = view

var bounds = view.frame
bounds.origin = CGPointZero
bounds.origin = CGPoint.zero

extensionView?.frame = bounds
extensionController.view.frame = bounds
extensionController.view.addSubview(view)
extensionController.expand()
_ = extensionController.expand()

extensionController.view.superview?.bringSubviewToFront(extensionController.view)
extensionController.view.superview?.bringSubview(toFront: extensionController.view)
updateContentInsets()
}

public func viewWillAppear(animated: Bool) {
open func viewWillAppear(_ animated: Bool) {
expand()
}

public func viewDidLayoutSubviews() {
open func viewDidLayoutSubviews() {
updateContentInsets()
}

public func viewWillDisappear(animated: Bool) {
open func viewWillDisappear(_ animated: Bool) {
expand()
}

public func updateValues() {
open func updateValues() {
isUpdatingValues = true

var scrolledToTop = false
Expand All @@ -177,29 +175,29 @@ public class HidingNavigationBarManager: NSObject, UIScrollViewDelegate, UIGestu
isUpdatingValues = false
}

public func shouldScrollToTop(){
open func shouldScrollToTop(){
// update content Inset
let top = statusBarHeight() + navBarController.totalHeight()
updateScrollContentInsetTop(top)

navBarController.snap(false, completion: nil)
tabBarController?.snap(false, completion: nil)
_ = navBarController.snap(false, completion: nil)
_ = tabBarController?.snap(false, completion: nil)
}

public func contract(){
navBarController.contract()
tabBarController?.contract()
open func contract(){
_ = navBarController.contract()
_ = tabBarController?.contract()

previousYOffset = CGFloat.NaN
previousYOffset = CGFloat.nan

handleScrolling()
}

public func expand() {
navBarController.expand()
tabBarController?.expand()
open func expand() {
_ = navBarController.expand()
_ = tabBarController?.expand()

previousYOffset = CGFloat.NaN
previousYOffset = CGFloat.nan

handleScrolling()
}
Expand All @@ -208,56 +206,56 @@ public class HidingNavigationBarManager: NSObject, UIScrollViewDelegate, UIGestu

func applicationWillEnterForeground() {
switch onForegroundAction {
case .Show:
navBarController.expand()
tabBarController?.expand()
case .Hide:
navBarController.contract()
tabBarController?.contract()
case .show:
_ = navBarController.expand()
_ = tabBarController?.expand()
case .hide:
_ = navBarController.contract()
_ = tabBarController?.contract()
default:
break;
}
}

//MARK: Private methods

private func isViewControllerVisible() -> Bool {
return viewController.isViewLoaded() && viewController.view.window != nil
fileprivate func isViewControllerVisible() -> Bool {
return viewController.isViewLoaded && viewController.view.window != nil
}

private func statusBarHeight() -> CGFloat {
if UIApplication.sharedApplication().statusBarHidden {
fileprivate func statusBarHeight() -> CGFloat {
if UIApplication.shared.isStatusBarHidden {
return 0
}

let statusBarSize = UIApplication.sharedApplication().statusBarFrame.size
let statusBarSize = UIApplication.shared.statusBarFrame.size
return min(statusBarSize.width, statusBarSize.height)
}

private func shouldHandleScrolling() -> Bool {
fileprivate func shouldHandleScrolling() -> Bool {
// if scrolling down past top
if scrollView.contentOffset.y <= -scrollView.contentInset.top && currentState == .Open {
return false
}

// if refreshing
if refreshControl?.refreshing == true {
if refreshControl?.isRefreshing == true {
return false
}

let scrollFrame = UIEdgeInsetsInsetRect(scrollView.bounds, scrollView.contentInset)
let scrollableAmount: CGFloat = scrollView.contentSize.height - CGRectGetHeight(scrollFrame)
let scrollableAmount: CGFloat = scrollView.contentSize.height - scrollFrame.height
let scrollViewIsSuffecientlyLong: Bool = scrollableAmount > navBarController.totalHeight() * 3

return isViewControllerVisible() && scrollViewIsSuffecientlyLong && !isUpdatingValues
}

private func handleScrolling(){
fileprivate func handleScrolling(){
if shouldHandleScrolling() == false {
return
}

if isnan(previousYOffset) == false {
if previousYOffset.isNaN == false {
// 1 - Calculate the delta
var deltaY = previousYOffset - scrollView.contentOffset.y

Expand All @@ -268,7 +266,7 @@ public class HidingNavigationBarManager: NSObject, UIScrollViewDelegate, UIGestu
}

/* rounding to resolve a dumb issue with the contentOffset value */
let end = floor(scrollView.contentSize.height - CGRectGetHeight(scrollView.bounds) + scrollView.contentInset.bottom - 0.5)
let end = floor(scrollView.contentSize.height - scrollView.bounds.height + scrollView.contentInset.bottom - 0.5)
if previousYOffset > end {
deltaY = max(0, deltaY - previousYOffset + end)
}
Expand Down Expand Up @@ -302,8 +300,8 @@ public class HidingNavigationBarManager: NSObject, UIScrollViewDelegate, UIGestu
}

// 6 - Update the shyViewController
navBarController.updateYOffset(deltaY)
tabBarController?.updateYOffset(deltaY)
_ = navBarController.updateYOffset(deltaY)
_ = tabBarController?.updateYOffset(deltaY)
}

// update content Inset
Expand All @@ -313,9 +311,9 @@ public class HidingNavigationBarManager: NSObject, UIScrollViewDelegate, UIGestu

// update the visible state
let state = currentState
if CGPointEqualToPoint(navBarController.view.center, navBarController.expandedCenterValue()) && CGPointEqualToPoint(extensionController.view.center, extensionController.expandedCenterValue()) {
if navBarController.view.center.equalTo(navBarController.expandedCenterValue()) && extensionController.view.center.equalTo(extensionController.expandedCenterValue()) {
currentState = .Open
} else if CGPointEqualToPoint(navBarController.view.center, navBarController.contractedCenterValue()) && CGPointEqualToPoint(extensionController.view.center, extensionController.contractedCenterValue()) {
} else if navBarController.view.center.equalTo(navBarController.contractedCenterValue()) && extensionController.view.center.equalTo(extensionController.contractedCenterValue()) {
currentState = .Closed
}

Expand All @@ -324,7 +322,7 @@ public class HidingNavigationBarManager: NSObject, UIScrollViewDelegate, UIGestu
}
}

private func updateContentInsets() {
fileprivate func updateContentInsets() {
let navBarBottomY = navBarController.view.frame.origin.y + navBarController.view.frame.size.height
let top: CGFloat
if extensionController.isContracted() == false {
Expand All @@ -335,7 +333,7 @@ public class HidingNavigationBarManager: NSObject, UIScrollViewDelegate, UIGestu
updateScrollContentInsetTop(top)
}

private func updateScrollContentInsetTop(top: CGFloat){
fileprivate func updateScrollContentInsetTop(_ top: CGFloat){
if viewController.automaticallyAdjustsScrollViewInsets {
var contentInset = scrollView.contentInset
contentInset.top = top
Expand All @@ -347,7 +345,7 @@ public class HidingNavigationBarManager: NSObject, UIScrollViewDelegate, UIGestu
delegate?.hidingNavigationBarManagerDidUpdateScrollViewInsets(self)
}

private func handleScrollingEnded(velocity: CGFloat) {
fileprivate func handleScrollingEnded(_ velocity: CGFloat) {
let minVelocity: CGFloat = 500.0
if isViewControllerVisible() == false || (navBarController.isContracted() && velocity < minVelocity) {
return
Expand All @@ -363,41 +361,41 @@ public class HidingNavigationBarManager: NSObject, UIScrollViewDelegate, UIGestu

let deltaY = navBarController.snap(contracting, completion: nil)
let tabBarShouldContract = deltaY < 0
tabBarController?.snap(tabBarShouldContract, completion: nil)
_ = tabBarController?.snap(tabBarShouldContract, completion: nil)

var newContentOffset = scrollView.contentOffset
newContentOffset.y -= deltaY

let contentInset = scrollView.contentInset
let top = contentInset.top + deltaY

UIView.animateWithDuration(0.2){
UIView.animate(withDuration: 0.2, animations: {
self.updateScrollContentInsetTop(top)
self.scrollView.contentOffset = newContentOffset
}
})

previousYOffset = CGFloat.NaN
previousYOffset = CGFloat.nan
}
}

//MARK: Scroll handling

func handlePanGesture(gesture: UIPanGestureRecognizer){
func handlePanGesture(_ gesture: UIPanGestureRecognizer){
switch gesture.state {
case .Began:
case .began:
topInset = navBarController.view.frame.size.height + extensionController.view.bounds.size.height + statusBarHeight()
handleScrolling()
case .Changed:
case .changed:
handleScrolling()
default:
let velocity = gesture.velocityInView(scrollView).y
let velocity = gesture.velocity(in: scrollView).y
handleScrollingEnded(velocity)
}
}

//MARK: UIGestureRecognizerDelegate

public func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
open func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}

Expand Down
Loading

0 comments on commit 0268999

Please sign in to comment.