Prevent animation on UIPopover dismissed by tap outside? - ios

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
}

Related

How to update view behind the popover view on dismissal of the popover?

I have a View and a popover that appears on top of it, which alters data. I am trying to update the view/run a function on the main view (that is under the popover) once the popover is dismissed. I have tried numerous things including viewwillappear, but it isn't being registered as technically the view doesn't disappear since the popover is just above (And you can see part of the view from behind). If anyone can suggest how to call a function on the parent view when dismissing the popover (without crashing the app, as most of my attempts have), I would be very grateful! Thanks.
Update: I am attempting to do this with a modally presented vc now, and have attempted to use protocol callbacks but to no avail. Below is the code.
protocol MainVCDelegate: class {
func pushIt()
}
in the modally pushed view:
weak var delegate: MainVCDelegate?
#IBAction func changePartnerButton(_ sender: Any) {
delegate?.pushIt()
dismiss(animated: false)
}
in the main VC I implement the protocol and create the function to be run, but nothing happens.
In iOS 13 and iOS 14, you set yourself as the popover's presentation controller's delegate and implement presentationControllerDidDismiss. In iOS 12 and before, you set yourself as the popover's popover presentation controller's delegate and implement popoverPresentationControllerDidDismissPopover.

Is there any method like "popoverPresentationControllerWillDismissPopover"

There is only 1 method about dissmissing the popover in UIPopoverPresentationControllerDelegate, which named "popoverPresentationControllerDidDismissPopover".
I am making some UI update in this method. However,it would spend a little time to dismissing the popover.
Is there any way to make my UI updates before the popover is get dismissed?
Try this delegate method,
func popoverPresentationControllerShouldDismissPopover(popoverPresentationController: UIPopoverPresentationController) -> Bool
and return YES by default, this will be called before the pop over gets dismissed, I mean before the animation happens.

UIAlertController's Dismissal

I've implemented a navigation mediator singleton in my application. The mediator keeps a reference to the primary view controller to launch view controller transitions from. So to present a view controller, the consumer would call the navigation mediator to do this. Same with dismissal so that it can reset the primary view controller.
The problem I am running into is with presenting a UIAlertController. I cannot dismiss this controller through my navigation mediator because it is dismissed automatically when a button is tapped, therefore losing the ability to reset the primary view controller when it is dismissed.
The only solution I've come up with is the create an extension on UIAlertController to override viewWillDisappear which resets the primary view controller like below. Is there a way to cancel the default dismissal behaviour?
extension UIAlertController {
public override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
NavigationMediator.resetPrimaryViewController(self.presentingViewController)
}
}
No, but you can respond to the event before it will finish. UIALertViewDelegate. alertView:willDismissWithButtonIndex:
Else build your own AlertView.

How to call function on UIPopViewController dismiss in iPad

I am using UIPopViewController in iPad application,I can dismiss popviewcontroller using tap on screen.But,I am trying to call function for dismiss,is that possible?How can I call function?Please help me.
If you are trying to dismiss the popover programatically, you can simply call:
[popover dismissPopoverAnimated:YES];
If you are trying to detect whether a user has dismissed a popover by tapping on the screen, you can make use of the UIPopoverControllerDelegate method popoverControllerDidDismissPopover:
First, set the viewController which presents the popover as delegate:
popover.delegate = self;
Then implement the method:
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
{
//Perform necessary action here.
}
Have a look at the UIPopoverControllerDelegate reference here.

iOS: How to persent a modalview as the UIPopover style

I want to persent a modalwindow, I use the PresentModalViewController and set the ModalPresentationStyle to UIModalPresentationStyle.FormSheet.
But how to persent the window as a pop layer such as the UIpopover, it allows the users to dismiss the popwindow just touch the outside of the popwindow area.
BTW, how to modify the UIpopover dark frame and set the UIPopoverArrowDirection to nothing ?
The way that I do this is to implement the popoverControllerShouldDismissPopover method from the UIPopoverControllerDelegate in my parent view controller class, and just return a NO. This will prevent the popover from disappearing when the user taps somewhere other than on the popover.
#pragma mark - UIPopoverControllerDelegate
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController
{
return NO;
}

Resources