Descobrir o quadro UIBarButtonItem na janela?

UIBarButtonItem não estende UIView , portanto, não há nada como uma propriedade de quadro.

Mas existe alguma maneira de obter o quadro CGRect relativo ao aplicativo UIWindow ?

Você gosta de usar APIs privadas ? Se sim,

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

Claro que ninguém quer isso ao segmentar a AppStore. Um método mais confiável , e também usa resources não documentados, mas vai passar no teste da Apple, é percorrer as subvisualizações para procurar o item de botão correspondente.

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

O index é o índice para o item de barra na matriz de .items , depois de remover todos os itens em branco . Isso pressupõe que os botões estão organizados em ordem crescente, o que pode não ser. Um método mais confiável é classificar a matriz de buttons aumentando o valor de .origin.x . É claro que isso ainda pressupõe que o item de botão da barra deve herdar a class UIControl e são subvisualizações diretas da barra de ferramentas / barra de navegação, o que, novamente, pode não ser.


Como você pode ver, há muita incerteza ao lidar com resources não documentados. No entanto, você só quer aparecer algo sob o dedo certo? O .action do .action pode ser um seletor do formulário:

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

observe o argumento do evento – você pode obter a posição de contato com

 [[event.allTouches anyObject] locationInView:theWindow] 

ou a vista de botão com

 [[event.allTouches anyObject] view] 

Portanto, não há necessidade de iterar as subvisualizações ou usar resources não documentados para o que você deseja fazer.

Eu não vi essa opção postada (o que na minha opinião é muito mais simples), então aqui está:

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

No iOS 3.2, há uma maneira muito mais fácil de mostrar um popover de Action Sheet a partir de um botão da barra de ferramentas. Apenas faça algo assim:

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

Esta é a implementação que uso para o meu projeto 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 

Consegui que o WEpopover de Werner Altewischer funcionasse passando a barra de ferramentas junto com o
UIBarButton: Mod está no 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]; } 

Contanto que UIBarButtonItem (e UITabBarItem ) não herde do UIView – por razões históricas, o UIBarItem herda do NSObject – essa loucura continua (no momento em que escrevo, iOS 8.2 e contando …)

A melhor resposta neste tópico é obviamente a do KennyTM . Não seja bobo e use a API privada para encontrar a visualização.

Aqui está uma solução Swift oneline para obter uma matriz ordenada origin.x (como a resposta de Kenny sugere):

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

A matriz agora é origin.x classificada com os frameworks UIBarButtonItem .

(Se você sentir necessidade de ler mais sobre as lutas de outras pessoas com o UIBarButtonItem, eu recomendo o post do blog de Ash Furrow de 2012: Explorando o UIBarButtonItem )

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

Você pode obtê-lo da exibição UINavigationBar. O navigationBar é um UIView que possui 2 ou 3 subvisualizações customizadas para as partes na barra.

Se você sabe que o UIBarButtonItem é mostrado atualmente na barra de navegação à direita, você pode obter seu quadro a partir da matriz de subvisualizações da navbar.

Primeiro você precisa do navigationBar que você pode obter do navigationController que você pode obter do UIViewController. Em seguida, encontre a subview mais correta:

 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 

Eu não compilei este código para YMMV.

Esta não é a melhor solução e, de certo ponto de vista, não é a solução certa e não podemos fazer como seguir porque UIBarBattonItem implicitamente, mas você pode tentar fazer algo como:

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

como resultado eu cheguei em seguida:

ponto {289, 22}

insira a descrição da imagem aqui

Antes de implementar este código, certifique-se de chamar [window makeKeyAndVisible] no seu application:didFinishLaunchingWithOptions: delegado do 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; } } 

Eu segurei da seguinte forma:

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