2010-06-08 50 views

回答

125

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

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

当然针对AppStore的时候没有人愿意这样。 A 更不可靠方法,也使用未公开的功能,但将通过苹果的测试,是循环通过子视图来查找相应的按钮项。

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] 
的按钮来查看

因此,不需要迭代子视图或使用未记录的功能来执行您想要的操作。

+5

我忘记有关该事件的参数。这显然是最好的选择。 – progrmr 2010-06-14 16:09:52

+1

事件参数ftw。非常感谢。 – 2010-07-29 04:49:15

+0

不错的。谢谢! – Kalle 2011-03-30 11:18:51

1

您可以从UINavigationBar视图中获取它。 navigationBar是一个UIView,其中有2个或3个自定义subviews用于栏上的零件。

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

首先您需要navigationBar,您可以从navigationController中获得这些信息,您可以从UIViewController中获取该信息。然后找到最右边的子视图:

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

在iOS 3.2中,通过工具栏按钮显示一个操作页面弹出窗口有一个更简单的方法。仅仅做这样的事情:

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

这只适用于iPad。 – 2013-05-26 20:56:34

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 
+1

不幸的是,这至少有时不起作用。我有一个以编程方式创建的UIBarButtonItems,我发现当customView设置为非零然后为零时,栏按钮项消失,[parentView.subviews objectAtIndex:indexOfView]崩溃(indexOfView不小于subviews.count)。 – 18446744073709551615 2011-12-27 10:29:21

+0

这不适用于我 – Bogdan 2012-07-16 08:45:01

+0

我使用当前(和工作)实现编辑答案 – 2013-05-24 11:46:36

2

我能得到沃纳Altewischer的WEpopover通过传递了工具栏的工作随着
UIBarButton: 国防部在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]; 
} 
-1

在实施此代码之前,请务必在您的Applition代理application:didFinishLaunchingWithOptions:方法中拨打[window makeKeyAndVisible]

- (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; 
} 
} 
+0

“UIBarButtonItem”实例没有“bounds”属性。 – 2013-05-17 17:34:21

+0

代码不访问barButtonItem的边界。它正在访问barButtonItem中的自定义视图的边界。 – 2015-12-03 16:52:15

16

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

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

这不是一个好的解决方案,因为它使用Apple私有API。 – 2014-11-19 19:06:16

+0

valueForKey:是唯一使用的方法。它不是一个私人API。这里所做的全部工作就是假设苹果不保证苹果的执行情况。 – Gerard 2015-10-23 16:20:23

+0

@Gerard“view”是这里的私有API。 – bugloaf 2016-01-14 15:55:58

-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 
} 
+0

使用私有API,因此它不是一个好的解决方案。 – 2014-11-19 20:39:13

+0

“-valueForKey:是一种文档化的公共方法,KVC API提供了一种防止直接实例变量访问的方法,因此如果该值是可访问的,那么不会采取任何措施禁止访问,一个问题可能是未定义的值在iOS的未来版本中,为了解决这个问题,你可以将调用封装在一个try-block中,并且即使你觉得你不能在应用程序商店中使用它,这并不意味着有人针对越狱的设备在其应用中无法使用这种方法。“用户@ jeremy-w-sherman在另一篇文章中写道 – 2014-11-26 03:18:23

2

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

在这个线程中最好的答案显然是@KennyTM's。不要傻,并使用私有API来查找视图。

这里的一个ONELINE夫特溶液得到一个origin.x排序后的数组(如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斗争,我建议Ash Furrow's博客帖子从2012年:Exploring UIBarButtonItem

2
-(CGRect) getBarItemRc :(UIBarButtonItem *)item{ 
    UIView *view = [item valueForKey:@"view"]; 
    return [view frame]; 
} 
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

+0

使用tap操作中的event参数仍然是抓取tap时发生的最安全的方法。但如果你需要找出没有检测到水龙头框架,我会说这是一个很好的解决方案**如果**你检查rightBarButtonItem为respondsToSelector。 – leolobato 2016-03-11 09:53:40

+0

谢谢,好点 – gbk 2016-03-11 11:38:40