Get progress of UINavigationController swipe back
This is what seems to work:
private var currentTransitionCoordinator: UIViewControllerTransitionCoordinator?
@objc private func onGesture(sender: UIGestureRecognizer) {
switch sender.state {
case .began, .changed:
if let ct = navigationController?.transitionCoordinator {
currentTransitionCoordinator = ct
}
case .cancelled, .ended:
currentTransitionCoordinator = nil
case .possible, .failed:
break
}
if let currentTransitionCoordinator = currentTransitionCoordinator {
print(currentTransitionCoordinator.percentComplete)
}
}
After you let go there is no way to get progress though. I tried preserving the coordinator for a bit longer and printing values on timer but I get a crash even.
Anyway, I assume this is what you need.
TEST SCENARIO:
Create a new project and navigate to main storyboard. Add a navigation controller and set its root view controller to ViewController
in storyboard (remove the autogenerated root).
Then go to ViewController.swift and overwrite it with following:
import UIKit
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if let controller = navigationController, controller.viewControllers.count <= 1 { // Present it first time only
view.backgroundColor = UIColor.green
let newController = ViewController()
newController.view.backgroundColor = UIColor.red
navigationController?.interactivePopGestureRecognizer?.addTarget(newController, action: #selector(onGesture))
navigationController?.pushViewController(newController, animated: true)
}
}
private var currentTransitionCoordinator: UIViewControllerTransitionCoordinator?
@objc private func onGesture(sender: UIGestureRecognizer) {
switch sender.state {
case .began, .changed:
if let ct = navigationController?.transitionCoordinator {
currentTransitionCoordinator = ct
}
case .cancelled, .ended:
currentTransitionCoordinator = nil
case .possible, .failed:
break
}
if let currentTransitionCoordinator = currentTransitionCoordinator {
print(currentTransitionCoordinator.percentComplete)
}
}
}
You should be able to see percentage printed out as you drag your finger, dismissing currently pushed view controller.
How to enable back/left swipe gesture in UINavigationController after setting leftBarButtonItem?
First set delegate in viewDidLoad:
self.navigationController.interactivePopGestureRecognizer.delegate = self;
And then disable gesture when pushing:
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
[super pushViewController:viewController animated:animated];
self.interactivePopGestureRecognizer.enabled = NO;
}
And enable in viewDidDisappear:
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
Also, add UINavigationControllerDelegate
to your view controller.
Overriding back swipe gesture in UINavigationController
You can do this in a combination of the following:
Add a swipe gesture recognizer to your view controller:
Add the following to your view controller class:
import UIKit
class SwipeBackViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.interactivePopGestureRecognizer?.isEnabled = false
}
@IBAction func swipeback(_ sender: UISwipeGestureRecognizer) {
navigationController?.popToRootViewController(animated: true)
}
}
- The command in
viewDidLoad
disables the default swipe recogninzer in iOS - Then, the action associated with the swipe recognizer you added above handles the pop for you
My answer here goes into disabling the recognizer in more detail in case you have any questions on that.
iOS 7 uinavigationcontroller how to detect swipe?
The interactive pop gesture recognizer is exposed through UINavigationController
's interactivePopGestureRecognizer
property. You can add your own controller as a target of the gesture recognizer and respond appropriately:
@implementation MyViewController
...
- (void)viewDidLoad
{
[super viewDidLoad];
[self.navigationController.interactivePopGestureRecognizer addTarget:self
action:@selector(handlePopGesture:)];
}
- (void)handlePopGesture:(UIGestureRecognizer *)gesture
{
if (gesture.state == UIGestureRecognizerStateBegan)
{
// respond to beginning of pop gesture
}
// handle other gesture states, if desired
}
...
@end
How to disable back swipe gesture in UINavigationController on iOS 7
I found a solution:
Objective-C:
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
Swift 3+:self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
Swipe to go back only works on edge of screen?
Apple says here :
interactivePopGestureRecognizer
The gesture recognizer responsible for popping the top view controller
off the navigation stack. (read-only)@property(nonatomic, readonly) UIGestureRecognizer
*interactivePopGestureRecognizerThe navigation controller installs this gesture recognizer on its view
and uses it to pop the topmost view controller off the navigation
stack. You can use this property to retrieve the gesture recognizer
and tie it to the behavior of other gesture recognizers in your user
interface. When tying your gesture recognizers together, make sure
they recognize their gestures simultaneously to ensure that your
gesture recognizers are given a chance to handle the event.
So SloppySwiper library customise the UIPanGestureRecognizer
.
Check out the library SloppySwiper, which achieves this by using UIPanGestureRecognizer and by recreating the default animation.
SloppySwiper:-
UINavigationController delegate that allows swipe back gesture to be started from anywhere on the screen like instagram.
Usage of this library can be found here.
Cocoapods:- pod "SloppySwiper"
I test this library on ios7 and above. It works like a charm.
Changing back button in iOS 7 disables swipe to navigate back
IMPORTANT:
This is a hack. I would recommend taking a look at this answer.
Calling the following line after assigning the leftBarButtonItem
worked for me:
self.navigationController.interactivePopGestureRecognizer.delegate = self;
Edit:
This does not work if called in init
methods. It should be called in viewDidLoad
or similar methods.
Related Topics
How to Convert This Opengl Pointer Math to Swift
iOS Swift 2 Record Video Avcapturesession
How to Bridge Nsnumber to Float in JSON Parsing
Swift - Uipopovercontroller in iOS 8
How to Draw Geojson in Apple Maps as Overlay Using Swift 3
Items in File Provider Extension for iOS 11
Display UI (Storyboard Possibly) with Broadcast UI Extension
Gmsmarker Icon in the Top Left Corner of the View (Ios)
Save Depth Images from Truedepth Camera
How Is It I Can Animate the Change in Bar Tint Color of a Uinavigationbar But Not a Uitabbar
How to Store JSON Decodable Values into Coredata Using Swift
How to Run My Performance Tests More Than Ten Times
How to Test If "Allow Full Access" Permission Is Granted from Containing App