I am using a pan gesture recognizer to dismiss a UINavigationController. I'm using the code from here, with modifications to fit my NavigationController and I am also adding the gesture recognizer to the actual VC inside the container view.
Everything works fine except the fact that when I swipe down, the navigation bar changes its position whenever the y value is > 0.0.
What I think is happening is that the navigation bar is attached to the top safe area, and when it leaves that top safe area, it automatically resizes itself to the top of the view.
How could I simply implement it so that the size of the navigation bar either extends underneath the safe area at the top or completely disregards it, and instead constraints to the view that it's in?
Here are the pictures:
Here is the code I am using for my UINavigationController
//
// PannableViewController.swift
//
import UIKit
class PannableViewController: UINavigationController {
public var minimumVelocityToHide = 1500 as CGFloat
public var minimumScreenRatioToHide = 0.5 as CGFloat
public var animationDuration = 0.2 as TimeInterval
override func viewDidLoad() {
super.viewDidLoad()
// Listen for pan gesture
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(onPan(_:)))
if let lastVC = self.childViewControllers.last {
lastVC.view.addGestureRecognizer(panGesture)
}
}
func slideViewVerticallyTo(_ y: CGFloat) {
self.view.frame.origin = CGPoint(x: 0, y: y)
}
@objc func onPan(_ panGesture: UIPanGestureRecognizer) {
switch panGesture.state {
case .began, .changed:
// If pan started or is ongoing then
// slide the view to follow the finger
let translation = panGesture.translation(in: view)
let y = max(0, translation.y)
self.slideViewVerticallyTo(y)
break
case .ended:
// If pan ended, decide it we should close or reset the view
// based on the final position and the speed of the gesture
let translation = panGesture.translation(in: view)
let velocity = panGesture.velocity(in: view)
let closing = (translation.y > self.view.frame.size.height * minimumScreenRatioToHide) ||
(velocity.y > minimumVelocityToHide)
if closing {
UIView.animate(withDuration: animationDuration, animations: {
// If closing, animate to the bottom of the view
self.slideViewVerticallyTo(self.view.frame.size.height)
}, completion: { (isCompleted) in
if isCompleted {
// Dismiss the view when it dissapeared
self.dismiss(animated: false, completion: nil)
}
})
} else {
// If not closing, reset the view to the top
UIView.animate(withDuration: animationDuration, animations: {
self.slideViewVerticallyTo(0)
})
}
break
default:
// If gesture state is undefined, reset the view to the top
UIView.animate(withDuration: animationDuration, animations: {
self.slideViewVerticallyTo(0)
})
break
}
}
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nil, bundle: nil)
self.modalPresentationStyle = .overFullScreen;
self.modalTransitionStyle = .coverVertical;
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.modalPresentationStyle = .overFullScreen;
self.modalTransitionStyle = .coverVertical;
}
}