I've got a UINavigationController that can pop to multiple VC's. I want to disallow the 'slide to pop' slide animation if the VC to pop to is of a certain class. How do I do that?
Disabling the slide animation for the entire navigationcontroller can be done like this:
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
But I want that only to be true if the destination is of a certain class.
I haven't tried this but the following should work:
UINavigationController has the interactivePopGestureRecognizer property.
In the viewDidAppear method of the view controller that you don't want to allow the "slide to pop", do:
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
Then in the same view controller's viewDidDisappear method, call:
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
Related
I'm having a weird reaction in 1 of my view when swipe to back.
It did not go back to my previous page but other pages does not have this issue. Also, it perform the previous page viewWillAppear code after the swipe.
I did not set any custom back buttons for the views but it is having different effect.
--Edit--
In my previous page that call the affecting page
ViewControllerA *view = [[ViewControllerA alloc] initWithNibName:#"ViewControllerA" bundle:nil];
[self.navigationController pushViewController:view animated:YES];
In my affecting page I only declare viewDidLoad function.
All my navigation for other classes is using the above calling.
By normal clicking the back action at the navigation bar, it will go back to the previous page normally.
--Edit 2--
My current setup is ViewA > ViewB > ViewC where ViewC is where the bug is happening.
At ViewB when I swipe at the edge, it can go back to ViewA.
At ViewC when I swipe at the edge, viewWillAppear in ViewB called but ViewB is not shown.
Tried putting #kaushal answer
if ([self respondsToSelector:#selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
self.navigationController.interactivePopGestureRecognizer.delegate; //check UIGestureRecognizerDelegate delegate set properly.
}
in both ViewB and ViewC but it did not trigger.
--Edit 3--
I tested my other features flow and it seems that some have this same problem upon entering the third view and some is on the forth view.
In ViewDidAppear: use this code :
if ([self respondsToSelector:#selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
self.navigationController.interactivePopGestureRecognizer.delegate; //check UIGestureRecognizerDelegate delegate set properly.
}
And check UIGestureRecognizerDelegate is not nil.
In my universal iOS 8 app, I am presenting a popover using using UIPopoverPresentationController as seen below from prepareForSegue:
FavoriteNameViewController *nameVC = segue.destinationViewController;
UIPopoverPresentationController *popPC = nameVC.popoverPresentationController;
popPC.delegate = self;
And with this delegate method.
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
return UIModalPresentationNone;
}
In this particular case, I'm presenting a view controller that looks like an alert, but isn't.
Now my issue is that the user can click outside of this popover and it gets dismissed. There's no real problem with that except that's not how alerts work and I would like this to emulate an alert.
I see that UIPopoverControllerDelegate had a method called popoverControllerShouldDismissPopover:, but UIPopoverPresentationControllerDelegate doesn't have that method, and I believe I need to use the latter.
You need to set the popover controller's passthroughViews to nil and the view controller's modalInPopover to YES.
Try the following in your view
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
return YES;
}
I have two UIViewControllers, A and B.
A is hiding the UINavigationBar and B is not.
When animating (with the default animation) from A to B, the navigation bar has to become visible. The navigation bar just pops in at some point (viewWillAppear or viewDidAppear) instead of sliding in with the UIViewController B.
When going back from B to A, the navigation bar is smoothly sliding back out.
How can I achieve the desired effect when animating from A to B?
In ViewController B, one has to simply do:
-(void) viewWillAppear:(BOOL)animated {
[super viewWillAppear: animated];
[self.navigationController setNavigationBarHidden: NO animated: YES];
}
I wasn't aware that this also controls the animation while doing a full view controller transition. I thought it only controls animation the navigation bar out to the top and back in.
You can try the following:
Use a instance variable to do this:
self.navigationController setNavigationBarHidden:hide animated:animated];
_shouldHideStatusBar = hide;
And implement the following function:
- (BOOL)prefersStatusBarHidden{
return _shouldHideStatusBar;
}
The setNavigationBarHidden:animated function will automatically call prefersStatusBarHidden function. If it doesn't you can call it with the following UIViewController's method:
[self setNeedsStatusBarAppearanceUpdate];
And of course you can choose your status bar hiding animation style with:
- (UIStatusBarAnimation) preferredStatusBarUpdateAnimation {
return UIStatusBarAnimationSlide;
}
Let me know if this helps. Good luck!!
(I got this answer here: How to slide in/out statusBar and navigationBar simultaneously?)
When a user taps outside the popover, the dismissal is animated. Is there a way to set that dismissal animation to NO? I have googled and searched on Stack extensively.
The docs for UIPopover state:
When displayed, taps outside of the popover window cause the popover
to be dismissed automatically. To allow the user to interact with the
specified views and not dismiss the popover, you can assign one or
more views to the passthroughViews property. Taps inside the popover
window do not automatically cause the popover to be dismissed. Your
view and view controller code must handle actions and events inside
the popover explicitly and call the dismissPopoverAnimated: method as
needed.
I have implemented the dismissPopoverAnimated: method with NO and that works great for all the cases when I call that method.
The problem is when a user taps outside the popover to dismiss, dismissPopoverAnimated: is not called.
taps outside of the popover window cause the popover
to be dismissed automatically.
And that dismissal is animated. There seems to be no way to control that dismissal. I am using the popover to present a color picker for a drawing app. Taps to draw are not registered until the popover has finished animating out. This creates a noticeable delay as you are not able to draw immediately but must wait for the animation to complete.
I thought that - (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController could work but there is no way AFAIK to set the animation property in this method. Just return yes or no.
Is there a different method I can implement to be able to set the animation to NO?
In the view controller that presents your UIPopoverController, conform to the UIPopoverControllerDelegate protocol and implement the following delegate method. I just tested this and it does dismiss the popover without animation.
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController
{
[self.myPopoverController dismissPopoverAnimated:NO];
return YES;
}
Just make sure that you have set the delegate of your popover controller to the view controller that implements this.
Swift 5
This will disable the animation, when we close the popOver by tapping outside.
extension YourViewController: UIPopoverPresentationControllerDelegate {
func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
// to prevent animation, we need to dismiss it manuallly with animated: false
presentationController.presentingViewController.dismiss(animated: false, completion: nil)
return true
}
}
On iOS 9+ as by default modalPresentationStyle = .Popover you can implement this method to prevent dismiss clicking out
public func popoverPresentationControllerShouldDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) -> Bool {
return false
}
I'm experiencing some weird behavior with hiding and showing the UINavigationBar.
In my viewWillAppear method I'm calling this:
self.navigationController.navigationBar.hidden = YES;
and when the user presses a button I'm calling this:
self.navigationController.navigationBar.hidden = NO;
and then swapping out the current view controller using the viewControllers property of a custom UINavigationController.
This works fine, but if I try to show the navigationBar using the same line in the viewWillDisappear method, it doesn't work. The navigationBar is still hidden.
I'm able to show/hide the status bar in viewWillDisappear using the following method:
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
but showing/hiding the UINavigationBar doesn't work!
EDIT: Also, self.navigationController.isNavigationBarHidden returns NO after I try to show the bar in viewWillDisappear but the bar is still hidden.
Any help would be greatly appreciated. Thank you!
Because you’ve already swapped the current view controller out of the stack, self.navigationController is probably nil when viewWillDisappear is called.
You're better off not messaging self.navigationController from viewWillDisappear as eager pointed out since it may be nil. Rather than holding on to a reference, I recommend editing the navigationBarHidden property always from within viewWillAppear as in this answer https://stackoverflow.com/a/27748007/2248638 . I have a BOOL navigationBarHidden property on my UIViewController base class so that I only need to set the property once for those view controllers which are hidden.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:self.navigationBarHidden animated:animated];
}