在窗口中找出UIBarButtonItem框架?

时间:2010-06-08 02:05:07

标签: iphone objective-c cocoa-touch uikit

UIBarButtonItem不会延伸UIView,因此没有像框架属性那样的内容。

但有什么方法可以得到相对于应用CGRect的{​​{1}}帧是什么?

11 个答案:

答案 0 :(得分:126)

你喜欢使用private API吗?如果是的话,

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

当然,在定位AppStore时没有人想要这个。一个更不可靠的方法,并且还使用了未记录的功能,但是将通过Apple的测试,就是遍历子视图以查找相应的按钮项。

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];

index是删除所有空白项后.items数组中条形项的索引。此假设按钮按递增顺序排列,可能不是。一种更可靠的方法是排序 buttons数组,增加.origin.x值。当然,这仍然假设条形按钮项必须继承UIControl类,并且是工具栏/导航栏的直接子视图,这也可能不是。


正如您所看到的,在处理未记录的功能时存在很多不确定性。但是,你只想在手指下弹出一些东西吗? UIBarButtonItem的.action可以是以下形式的选择器:

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

注意事件参数 - 您可以使用

获取触摸位置
[[event.allTouches anyObject] locationInView:theWindow]

或带

的按钮视图
[[event.allTouches anyObject] view]

因此,无需迭代子视图或使用未记录的功能来实现您的目标。

答案 1 :(得分:17)

我没有看到这个选项发布(在我看来更简单),所以这里是:

UIView *barButtonView = [barButtonItem valueForKey:@"view"];

答案 2 :(得分:8)

在iOS 3.2中,有一种更简单的方法可以从工具栏按钮显示“操作表”弹出窗口。仅仅做这样的事情:

- (IBAction)buttonClicked:(UIBarButtonItem *)sender event:(UIEvent *)event
{
 UIActionSheet *popupSheet;
 // Prepare your action sheet
 [popupSheet showFromBarButtonItem:sender animated:YES];
}

答案 3 :(得分:4)

这是我用于WEPopover项目的实现:(https://github.com/werner77/WEPopover):

@implementation UIBarButtonItem(WEPopover)

- (CGRect)frameInView:(UIView *)v {

    UIView *theView = self.customView;
    if (!theView.superview && [self respondsToSelector:@selector(view)]) {
        theView = [self performSelector:@selector(view)];
    }

    UIView *parentView = theView.superview;
    NSArray *subviews = parentView.subviews;

    NSUInteger indexOfView = [subviews indexOfObject:theView];
    NSUInteger subviewCount = subviews.count;

    if (subviewCount > 0 && indexOfView != NSNotFound) {
        UIView *button = [parentView.subviews objectAtIndex:indexOfView];
        return [button convertRect:button.bounds toView:v];
    } else {
        return CGRectZero;
    }
}
@end

答案 4 :(得分:3)

只要UIBarButtonItem(和UITabBarItem)未从UIView继承 - 由于历史原因UIBarItem继承自NSObject - 这种疯狂仍在继续(如本文的写作,iOS 8.2和计数...)

这个帖子中的最佳答案显然是@KennyTM's。不要愚蠢并使用私有API来查找视图。

以下是获取origin.x排序数组的oneline Swift解决方案(如Kenny's answer建议):

    let buttonFrames = myToolbar.subviews.filter({
        $0 is UIControl
    }).sorted({
        $0.frame.origin.x < $1.frame.origin.x
    }).map({
        $0.convertRect($0.bounds, toView:nil)
    })

现在,数组origin.xUIBarButtonItem帧排序。

(如果您觉得有必要详细了解其他人与UIBarButtonItem的斗争,我建议您从2012年开始Ash Furrow's博文:Exploring UIBarButtonItem

答案 5 :(得分:2)

我能够让Werner Altewischer的WEpopover通过工具栏连同工作     UIBarButton:     Mod在WEPopoverController.m

- (void)presentPopoverFromBarButtonItem:(UIBarButtonItem *)item toolBar:(UIToolbar *)toolBar
               permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections 
                               animated:(BOOL)animated 
{
    self.currentUIControl = nil;
    self.currentView = nil;
    self.currentBarButtonItem = item;
    self.currentArrowDirections = arrowDirections;
    self.currentToolBar = toolBar;

    UIView *v = [self keyView];
    UIButton *button = nil;

    for (UIView *subview in toolBar.subviews) 
    {
        if ([[subview class].description isEqualToString:@"UIToolbarButton"])
        {
            for (id target in [(UIButton *)subview allTargets]) 
            {
                if (target == item) 
                {
                    button = (UIButton *)subview;
                    break;
                }
            }
            if (button != nil) break;
        }
    }

    CGRect rect = [button.superview convertRect:button.frame toView:v];

    [self presentPopoverFromRect:rect inView:v permittedArrowDirections:arrowDirections animated:animated];
}

答案 6 :(得分:2)

-(CGRect) getBarItemRc :(UIBarButtonItem *)item{
    UIView *view = [item valueForKey:@"view"];
    return [view frame];
}

答案 7 :(得分:1)

您可以从UINavigationBar视图中获取它。 navigationBar是一个UIView,它对条形图上的部件有2或3个自定义subviews

如果您知道UIBarButtonItem当前显示在右侧的导航栏中,您可以从导航栏的子视图数组中获取其帧。

首先,你需要navigationBar,你可以从你从UIViewController获得的navigationController获得。然后找到最正确的子视图:

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

我没有编译这个代码所以YMMV。

答案 8 :(得分:0)

这不是最佳解决方案,从某些角度来看,它不是正确的解决方案,因为我们隐式访问UIBarBattonItem内的对象,所以我们无法执行操作,但您可以尝试做类似的事情:

UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
[button setImage:[UIImage imageNamed:@"Menu_Icon"] forState:UIControlStateNormal];
[button addTarget:self action:@selector(didPressitem) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:button];
self.navigationItem.rightBarButtonItem = item;

CGPoint point = [self.view convertPoint:button.center fromView:(UIView *)self.navigationItem.rightBarButtonItem];
//this is like view because we use UIButton like "base" obj for 
//UIBarButtonItem, but u should note that UIBarButtonItem base class
//is NSObject class not UIView class, for hiding warning we implicity
//cast UIBarButtonItem created with UIButton to UIView
NSLog(@"point %@", NSStringFromCGPoint(point));

结果我接下来:

  

指向{289,22}

enter image description here

答案 9 :(得分:-1)

在实施此代码之前,请务必在Applition委托[window makeKeyAndVisible]方法中调用application:didFinishLaunchingWithOptions:

- (void) someMethod
{
    CGRect rect = [barButtonItem convertRect:barButtonItem.customview.bounds toView:[self keyView]];
}

- (UIView *)keyView {
UIWindow *w = [[UIApplication sharedApplication] keyWindow];
if (w.subviews.count > 0) {
    return [w.subviews objectAtIndex:0];
} else {
    return w;
}
}

答案 10 :(得分:-1)

我按如下方式处理:

- (IBAction)buttonClicked:(UIBarButtonItem *)sender event:(UIEvent *)event
{
    UIView* view = [sender valueForKey:@"view"]; //use KVO to return the view
    CGRect rect = [view convertRect:view.bounds toView:self.view];
    //do stuff with the rect
}