I have a UIBarButtonItem
with UIButton
as custom view.
The UIButton
has a addTarget:action:
on it. In the action I present a popover. I'm currently presenting from the sender.frame
(the UIButton
's Frame) I want to Present from the UIBarButtonItem
instead.
How can I access the UIBarButtonItem
from the UIButton
?
If you have set your UIButton
as the customView
of a UIBarButtonItem
, or a child of the custom view, then you can walk up the view hierarchy from your button until you find the UIToolbar
or UINavigationBar
that contains the button, then search the bar's items for the one whose custom view is the button (or an ancestor of the button).
Here's my completely untested code for doing that. You would call [[self class] barButtonItemForView:myButton]
to get the item containing your button.
+ (BOOL)ifBarButtonItem:(UIBarButtonItem *)item containsView:(UIView *)view storeItem:(UIBarButtonItem **)outItem {
UIView *customView = item.customView;
if (customView && [view isDescendantOfView:customView]) {
*outItem = item;
return YES;
} else {
return NO;
}
}
+ (BOOL)searchBarButtonItems:(NSArray *)items forView:(UIView *)view storeItem:(UIBarButtonItem **)outItem {
for (UIBarButtonItem *item in items) {
if ([self ifBarButtonItem:item containsView:view storeItem:outItem])
return YES;
}
return NO;
}
+ (UIBarButtonItem *)barButtonItemForView:(UIView *)view {
id bar = view;
while (bar && !([bar isKindOfClass:[UIToolbar class]] || [bar isKindOfClass:[UINavigationBar class]])) {
bar = [bar superview];
}
if (!bar)
return nil;
UIBarButtonItem *item = nil;
if ([bar isKindOfClass:[UIToolbar class]]) {
[self searchBarButtonItems:[bar items] forView:view storeItem:&item];
}
else {
UINavigationItem *navItem = [bar topItem];
if (!navItem)
return nil;
[self ifBarButtonItem:navItem.backBarButtonItem containsView:view storeItem:&item]
|| [self ifBarButtonItem:navItem.leftBarButtonItem containsView:view storeItem:&item]
|| [self ifBarButtonItem:navItem.rightBarButtonItem containsView:view storeItem:&item]
|| ([navItem respondsToSelector:@selector(leftBarButtonItems)]
&& [self searchBarButtonItems:[(id)navItem leftBarButtonItems] forView:view storeItem:&item])
|| ([navItem respondsToSelector:@selector(rightBarButtonItems)]
&& [self searchBarButtonItems:[(id)navItem rightBarButtonItems] forView:view storeItem:&item]);
}
return item;
}
First of all, why do you need to access the UIBarButtonItem
?
Then, to create a UIBarButtonItem
with a custom view I suggest you to create a category extension like the following (in this case the custom view is a UIButton
).
//UIBarButtonItem+Extension.h
+ (UIBarButtonItem*)barItemWithImage:(UIImage*)image title:(NSString*)title target:(id)target action:(SEL)action;
//UIBarButtonItem+Extension.m
+ (UIBarButtonItem*)barItemWithImage:(UIImage*)image title:(NSString*)title target:(id)target action:(SEL)action
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height);
button.titleLabel.textAlignment = UITextAlignmentCenter;
[button setBackgroundImage:image forState:UIControlStateNormal];
[button setTitle:title forState:UIControlStateNormal];
[button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem* barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button];
return [barButtonItem autorelease];
}
and the use it like this (first import UIBarButtonItem+Extension.h
):
UIBarButtonItem* backBarButtonItem = [UIBarButtonItem barItemWithImage:[UIImage imageNamed:@"YoutImageName"] title:@"YourTitle" target:self action:@selector(doSomething:)];
where the selector it's a method that is implemented inside the class (the target) that uses that bar button item.
Now inside the doSomething:
selector you could the following:
- (void)doSomething:(id)sender
UIButton* senderButton = (UIButton*)sender;
[popover presentPopoverFromRect:senderButton.bounds inView:senderButton...];
}
A category in this case it's useful to not duplicate code. Hope it helps.
P.S. I'm not using ARC but same considerations can be also applied.
Edit:
An easy solution to access the bar button item could be the following:
UIButton
UIBarButtonItem
(a weak one to avoid retaincycle)UIButton
when you create it.Maybe it could work, but I will prefer the first one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With