找出窗口中的 UIBarButtonItem 框架?

发布于 2024-11-28 15:06:52 字数 151 浏览 3 评论 0原文

UIBarButtonItem 不扩展 UIView,因此没有像框架属性那样的东西。

但是有什么方法可以获取相对于应用程序 UIWindowCGRect 框架吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

墨落画卷 2024-12-05 15:06:53

您喜欢使用私有 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 数组中栏项目的索引,删除所有空白项目后。这假设按钮按升序排列,但事实可能并非如此。更可靠的方法是以递增的 .origin.x 值对 buttons 数组进行排序。当然,这仍然假设栏按钮项必须继承 UIControl 类,并且是工具栏/导航栏的直接子视图,但也可能不是。


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

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

注意 event 参数 - 您可以获取触摸的位置

[[event.allTouches anyObject] locationInView:theWindow]

或按钮视图,

[[event.allTouches anyObject] view]

因此,无需迭代子视图或使用未记录的功能来完成您想要做的事情。

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.

一萌ing 2024-12-05 15:06:53

我没有看到这个选项发布(我认为这要简单得多),所以这里是:

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

I didn't see this option posted (which in my opinion is much simpler), so here it is:

UIView *barButtonView = [barButtonItem valueForKey:@"view"];
幻想少年梦 2024-12-05 15:06:53

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

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

In iOS 3.2, there's a much easier way to show an Action Sheet popover from a toolbar button. Merely do something like this:

- (IBAction)buttonClicked:(UIBarButtonItem *)sender event:(UIEvent *)event
{
 UIActionSheet *popupSheet;
 // Prepare your action sheet
 [popupSheet showFromBarButtonItem:sender animated:YES];
}
撩动你心 2024-12-05 15:06:53

这是我用于 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

This is the implementation I use for my WEPopover project: (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
忘你却要生生世世 2024-12-05 15:06:53

只要 UIBarButtonItem(和 UITabBarItem)不继承自 UIView — 由于历史原因,UIBarItem 继承自 NSObject——这种疯狂还在继续(截至撰写本文时,iOS 8.2 还在继续……)

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

这是一个获取 origin.x 排序数组的单行 Swift 解决方案(如 Kenny 的回答 建议的那样) :

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

该数组现在使用 UIBarButtonItem 框架进行 origin.x 排序。

(如果您觉得有必要阅读更多有关其他人与 UIBarButtonItem 的斗争的信息,我推荐 Ash Furrow 2012 年的博客文章: 探索UIBarButtonItem)

As long as UIBarButtonItem (and UITabBarItem) does not inherit from UIView—for historical reasons UIBarItem inherits from NSObject—this craziness continues (as of this writing, iOS 8.2 and counting ... )

The best answer in this thread is obviously @KennyTM's. Don't be silly and use the private API to find the view.

Here's a oneline Swift solution to get an origin.x sorted array (like Kenny's answer suggests):

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

The array is now origin.x sorted with the UIBarButtonItem frames.

(If you feel the need to read more about other people's struggles with UIBarButtonItem, I recommend Ash Furrow's blog post from 2012: Exploring UIBarButtonItem)

心清如水 2024-12-05 15:06:53

我能够通过传递工具栏和
来让 Werner Altewischer 的 WEpopover 工作
UIBar按钮:
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];
}

I was able to get Werner Altewischer's WEpopover to work by passing up the toolbar along with the
UIBarButton:
Mod is in 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];
}
青丝拂面 2024-12-05 15:06:53
-(CGRect) getBarItemRc :(UIBarButtonItem *)item{
    UIView *view = [item valueForKey:@"view"];
    return [view frame];
}
-(CGRect) getBarItemRc :(UIBarButtonItem *)item{
    UIView *view = [item valueForKey:@"view"];
    return [view frame];
}
无风消散 2024-12-05 15:06:53

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

如果您知道 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。

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.

安静被遗忘 2024-12-05 15:06:53

这不是最好的解决方案,从某些角度来看,这不是正确的解决方案,我们不能这样做,因为我们隐式访问 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} 点

在此处输入图像描述

This is not the best solution and from some point of view it's not right solution and we can't do like follow because we access to object inside UIBarBattonItem implicitly, but you can try to do something like:

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

as result i got next:

point {289, 22}

enter image description here

看透却不说透 2024-12-05 15:06:53

在实现此代码之前,请务必在 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;
}
}

Before implement this code, be sure to call [window makeKeyAndVisible] in your Applition delegate application:didFinishLaunchingWithOptions: method!

- (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;
}
}
香橙ぽ 2024-12-05 15:06:53

我是这样处理的:

- (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
}

I handled it as follows:

- (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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文