I'm trying to get the frame of a UIBarButtonItem, which just inherits from UIBarItem/NSObject.
-
You asked a question and posted the answer yourself... at same time... why so? – Anoop Vaidya Jan 04 '13 at 18:53
-
3I was trying to find this info online, but was only getting outdated info. Figured I'd post my work for others to benefit. – Jeremy White Jan 04 '13 at 18:55
-
1@AnoopVaidya It's [fine to answer your own question](http://meta.stackexchange.com/q/12513/158468) so long as you stick to SO's Q&A format. – Caleb Jan 04 '13 at 19:15
-
Thats is why I confirmed and pointed up his answer. But I am unaware of his answer, so I didn't vote there :( – Anoop Vaidya Jan 04 '13 at 19:16
4 Answers
In iOS 5.0, 5.1, and 6.0, use the following method. This method can be easily modified for use with a UIToolBar as well.
- (UIControl *) findBarButtonItem:(UIBarButtonItem *)barButtonItem
{
UINavigationBar *toolbar = self.navigationController.navigationBar;
UIControl *button = nil;
for (UIView *subview in toolbar.subviews) {
if ([subview isKindOfClass:[UIControl class]]) {
for (id target in [(UIControl *)subview allTargets]) {
if (target == barButtonItem) {
button = (UIControl *)subview;
break;
}
}
if (button != nil) break;
}
}
return button;
}
Usage:
UIControl *barButton = [self findBarButtonItem:myBarButtonItem];
CGRect barButtonFrame = barButton.frame;

- 2,818
- 6
- 38
- 74
-
5This is a clever approach to this problem but it does make a critical assumption that could change in the future. Anyone that uses this code must be aware that this code could break in any future iOS update. Be careful. – rmaddy Jan 04 '13 at 18:58
-
I agree that it's a bit risky. I've tested this in iOS 5.0, 5.1, and 6.0. – Jeremy White Jan 04 '13 at 19:07
This way works best for me:
UIView *targetView = (UIView *)[yourBarButton performSelector:@selector(view)];
CGRect rect = targetView.frame;

- 8,341
- 5
- 56
- 75
I know you posted this question for the purpose of posting the answer you found. I thought I would add an alternate solution that doesn't have the risk of breaking in a future iOS update.
If you create your UIBarButtonItem
using a custom view then you can access the customView
property of the UIBarButtonItem
. The frame
of the customView
will reflect its position in the toolbar or navbar.
Obviously this solution prevents you from using the standard system defined buttons. But you can easily replicate them with your own image.
Generally the custom view you would use would be a UIButton
with an appropriate icon image. One trick is to ensure you enable the button's showsTouchWhenHighlighted
property so you get the usual highlight effect.
Setup the UIButton
with the same target/action you would use on the UIBarButtonItem
.

- 314,917
- 42
- 532
- 579
-
How do you get the frame for the `customView`? I started with this answer https://stackoverflow.com/a/46465148/4833705 and I tried: (1)`guard let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) else { return }` ; (2)`guard let barView = self.navigationItem.rightBarButtonItem?.value(forKey: "view") as? UIView else { return}` ; (3)`guard let customView = barView.subviews.compactMap({ $0 as? UIButton }).first else { return }` : (4) `guard let rectInWindow = customView.superview?.superview?.convert(customView.frame, to: keyWindow) else { return }` but it stopped at (3). – Lance Samaria Feb 17 '21 at 06:00
-
Here's a way to do this without having to resort to undocumented behaviour or assumptions.
Instead of using a UIBarButtonSystemItem, use a UIBarButtonItem with a custom view. You can get the image from the UIBarButtonSystemItem using a technique like this one:

- 5,589
- 37
- 52