When presenting a popover you can set the passthroughViews
property to control which views that can receive touches while the popover is visible. Tapping on views that are not included will cause the popover to dismiss.
When presenting a popover from a UIBarButtonItem
iOS adds some views by default to the passthroughViews
property (see discussion below.).
To present a popover without any passthroughViews on iOS7 you could do the following:
UIPopoverController *popoverController = ...
[popoverController presentPopoverFromBarButtonItem:barButtonItem permittedArrowDirections:arrowDirections animated:animated];
// Needs to be set after presentation to take effect.
popoverController.passthroughViews = nil;
This no longer works on iOS 8 (up to 8.1.1 at the time of writing). The passthroughViews
assignment is ignored / overwritten.
Well on iOS8 you should actually use the new UIPopoverPresentationController
to present a popover instead. Let’s see if that works.
viewController.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController *presentationController = viewController.popoverPresentationController;
presentationController.barButtonItem = sender;
presentationController.passthroughViews = nil;
presentationController.permittedArrowDirections = UIPopoverArrowDirectionUp;
[self presentViewController:viewController animated:YES completion:NULL];
No, did not work either. Touches goes through to other bar buttons on the same toolbar without the popover dismissing. Trying to set passthroughViews
on the next line after presenting the view controller does not help either as it did on iOS7 with the UIPopoverController
.
Turns out waiting even longer than just the line below the presentation gets it working on iOS 8.
UIPopoverController *popoverController = ...
[popoverController presentPopoverFromBarButtonItem:barButtonItem permittedArrowDirections:arrowDirections animated:animated];
/// Wait 0.1 sec.
int64_t delta = (int64_t)(1.0e9 * 0.1);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delta), dispatch_get_main_queue(), ^{
popoverController.passthroughViews = nil;
});
With UIPopoverPresentationController
on iOS8 it gets a bit more elegant since we have a completion handler:
viewController.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController *presentationController = viewController.popoverPresentationController;
presentationController.barButtonItem = sender;
presentationController.permittedArrowDirections = UIPopoverArrowDirectionUp;
[self presentViewController:viewController animated:YES completion:^{
presentationController.passthroughViews = nil;
}];
Discussion
When presenting the popover providing a view and a frame instead of a bar button this issue with the passthroughViews
works as expected. The passthroughViews
can be set before presenting the popover and certainly without any delay. The reason could be that in this case the passthroughViews
property is not modified by default.
The docs on presenting from a bar button clearly states that the passthroughViews
property is tampered with.
Apple doc for UIPopoverController
method presentPopoverFromBarButtonItem:permittedArrowDirections:animated:
When presenting the popover, this method adds the toolbar that owns the button to the popover’s list of passthrough views.
For the new iOS8 UIPopoverPresentationController
’s barButtonItem
property the Apple doc states:
Prior to presentation, the presentation controller adds all sibling bar button items of the specified item (but not the item itself) to the popover’s list of passthrough views.
The difference is that with UIPopoverController
the whole UINavigationBar
/UIToolbar
that the bar button item belongs to is added by default as a passthrough view and with UIPopoverPresentationController
only the actual buttons on the same UINavigationBar
/UIToolbar
as the bar button item are added (so tapping between buttons dismisses the popover).
Both documentations then instructs:
If you want taps in the other bar button items to dismiss the popover, you must add code to the action handlers of those items to do so yourself.
Are they actually prohibiting the use of passthroughViews
when presenting from a bar button?
Much easier to set the passthroughViews
to nil
, right?
However, the HIG states:
When possible, allow people to close one popover and open a new one with one tap. This behavior is especially desirable when several different bar buttons each open a popover, because it prevents people from having to make extra taps.
So if there are other bar button items on the same toolbar that also presents a popover, setting the passthroughViews
to nil
is not suitable as a fast fix because it will force 2 taps to open the next popover.