-
Notifications
You must be signed in to change notification settings - Fork 462
Description
Situation
The app is build as a Tabbed App, so it has an UITabBarController as root view controller.
Each Tab has it's own view controller.
On the 4th tab we have an UITableViewController with an UINavigationBar with left and right UIBarButtonItems.
We've created an IBOutlet infoButton and present the pop tip by calling presentPointingAtBarButtonItem:animated::
[_poptipForManual presentPointingAtBarButtonItem:_infoButton
animated:YES];The pop tip is correctly shown:
However, when selecting another tab via the Tab Bar, the pop tip is still visible:
Analysis
Method presentPointingAtBarButtonItem:animated: determines the container view of the UIBarButtonItem and calls presentPointingAtView:inView:animated: with it.
The problem is it uses:
UIView *containerView = targetView.window;Where the app window is returned. This is the reason why the pop tip is visible on all tabs in a Tabbed App.
Solution
The proper container view is the superview of the parent view of the UIBarButtonItem.
The (public) parent view of an UIBarButtonItem is one of:
- UINavigationBar
- UIToolbar
- UITabBar
So the first step is to search upwards in the view hierarchy to determine whether the Bar Button is located in a Navigation Bar, Tool Bar or Tab Bar.
When a Navigation Bar, Tool Bar or Tab Bar is found, return it's superview and abort the search.
When no Navigation Bar, Tool Bar or Tab Bar is found, the default strategy is to use the app window (existing situation).
Here is my updated code for this method:
- (void)presentPointingAtBarButtonItem:(UIBarButtonItem *)barButtonItem animated:(BOOL)animated {
UIView *targetView = (UIView *)[barButtonItem performSelector:@selector(view)];
UIView *containerView = targetView;
// Search upwards in the view hierarchy to determine whether the Bar Button is located in a Navigation Bar, Tool Bar or Tab Bar:
while (containerView != nil) {
// Get super view:
containerView = containerView.superview;
// Check Class:
if ([containerView isKindOfClass:[UINavigationBar class]] ||
[containerView isKindOfClass:[UIToolbar class]] ||
[containerView isKindOfClass:[UITabBar class]]) {
// When a Navigation Bar, Tool Bar or Tab Bar is found, return it's superview and abort while-loop:
containerView = containerView.superview;
break;
}
}
// When no Navigation Bar, Tool Bar or Tab Bar is found:
if (nil == containerView) {
// Get the Bar Button's window:
containerView = targetView.window;
if (nil == containerView) {
NSLog(@"Cannot determine container view from UIBarButtonItem: %@", barButtonItem);
self.targetObject = nil;
return;
}
}
self.targetObject = barButtonItem;
[self presentPointingAtView:targetView
inView:containerView
animated:animated];
}Validation
This has been tested and now the pop tip is only shown on the view controller of the specific tab, which is the intended behaviour.
An added benefit is that this also works when presenting the pop tip from a Tab Bar button (this can be added to the ReadMe).
In this case the intended behaviour is that the pop tip is always visible, no matter which tab is selected.
Because the new code uses the superview of the UITabBar, this is the case.
In this example the pop tip is always presented from the 4th tab, even if it's not the selected tab:
[_poptipForConnectedTv presentPointingAtBarButtonItem:(UIBarButtonItem *)[self.tabBarController.tabBar.items objectAtIndex:3]
animated:YES]; 


