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