views:

524

answers:

3

Hey guys,

UIBarButtonItem does not extend UIView, so there is nothing like a frame property.

But is there any way I can get what is it's CGRect frame, relative to the application UIWindow?

A: 

No. Better question: why do you need to know? (What are you trying to do?)

Dave DeLong
I've got a little UIView subclass to do something like the pop over from the 3.2 SDK, but for 3.0 iPhone apps - so you see it could be quite handy to not hardcode the popover frame.
leolobato
A: 

You can get it from the UINavigationBar view. The navigationBar is a UIView which has 2 or 3 custom subviews for the parts on the bar.

If you know that the UIBarButtonItem is currently shown in the navbar on the right, you can get its frame from navbar's subviews array.

First you need the navigationBar which you can get from the navigationController which you can get from the UIViewController. Then find the right most subview:

UINavigationBar* navbar = curViewController.navigationController.navigationBar;
UIView* rightView = nil;

for (UIView* v in navbar.subviews) {
   if (rightView==nil) {
      rightView = v;
   } else if (v.frame.origin.x > rightView.frame.origin.x) {
      rightView = v;  // this view is further right
   }
}
// at this point rightView contains the right most subview of the navbar

I haven't compiled this code so YMMV.

progrmr
+6  A: 

Do you like to use private APIs? If yes,

UIView* view = thatItem.view;
return [view convertRect:view.bounds toView:nil];

Of course no one wants this when targeting the AppStore. A more unreliable method, and also uses undocumented features, but will pass Apple's test, is to loop through the subviews to look for the corresponding button item.

NSMutableArray* buttons = [[NSMutableArray alloc] init];
for (UIControl* btn in theToolbarOrNavbar.subviews)
  if ([btn isKindOfClass:[UIControl class]])
    [buttons addObject:btn];
UIView* view = [buttons objectAtIndex:index];
[buttons release];
return [view convertRect:view.bounds toView:nil];

The index is the index to your bar item in the array of .items, after removing all blank items. This assumes the buttons are arranged in increasing order, which may not be. A more reliable method is to sort the buttons array in increasing .origin.x value. Of course this still assumes the bar button item must inherit the UIControl class, and are direct subviews of the toolbar/nav-bar, which again may not be.


As you can see, there are a lot of uncertainty when dealing with undocumented features. However, you just want to pop up something under the finger right? The UIBarButtonItem's .action can be a selector of the form:

-(void)buttonClicked:(UIBarButtonItem*)sender event:(UIEvent*)event;

note the event argument — you can obtain the position of touch with

[[event.allTouches anyObject] locationInView:theWindow]

or the button view with

[[event.allTouches anyObject] view]

Therefore, there's no need to iterate the subviews or use undocumented features for what you want to do.

KennyTM
I forgot about the event parameter. That's obviously the best choice.
progrmr
Event parameter ftw. Thanks a lot.
Colin Barrett