Выясните, кадр UIBarButtonItem в окне?

UIBarButtonItem не распространяется UIView, поэтому нет ничего похожего на свойство кадра.

Но можно ли каким-либо образом получить кадр CGRect по отношению к приложению UIWindow?

Ответ 1

Вы любите использовать частный API? Если да,

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

Конечно, никто не хочет этого, ориентируясь на AppStore. A более ненадежный метод, а также использует недокументированные функции, но пройдет тест 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]

Поэтому нет необходимости перебирать подзапросы или использовать недокументированные функции для того, что вы хотите сделать.

Ответ 2

Я не заметил, что этот вариант опубликован (что, на мой взгляд, намного проще), так вот:

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

Ответ 3

В iOS 3.2 существует гораздо более простой способ показать всплывающее окно Action Sheet с панели инструментов. Просто сделайте что-нибудь вроде этого:

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

Ответ 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

Ответ 5

Я смог заставить Werner 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];
}

Ответ 6

Пока UIBarButtonItemUITabBarItem) не наследуется от UIView - по историческим причинам UIBarItem наследует от NSObject - это безумие продолжается (начиная с этой записи, iOS 8.2 и подсчета...)

Лучший ответ в этом потоке, очевидно, @KennyTM. Не будьте глупыми и используйте частный API, чтобы найти представление.

Здесь предлагается решение oneline Swift для получения отсортированного массива origin.x (например, Kenny 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.x сортируется с кадрами UIBarButtonItem.

(Если вам кажется, что вам нужно больше узнать о том, как другие люди борется с UIBarButtonItem, я рекомендую запись в блоге Ash Furrow's с 2012 года: Изучение UIBarButtonItem)

Ответ 7

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

Ответ 8

Вы можете получить его из представления UINavigationBar. NavigationBar - это UIView, у которого есть 2 или 3 пользовательских subviews для частей на панели.

Если вы знаете, что UIBarButtonItem в настоящее время отображается в навигационной панели справа, вы можете получить его фрейм из массива subviews navbar.

Сначала вам понадобится 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.

Ответ 9

Это не лучшее решение, и с некоторой точки зрения это не правильное решение, и мы не можем делать этого, потому что мы неявно обращаемся к объекту внутри 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));

В результате я получил следующее:

point {289, 22}

введите описание изображения здесь

Ответ 10

Прежде чем реализовать этот код, обязательно вызовите [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;
}
}

Ответ 11

Я обработал его следующим образом:

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