2010-06-08 12 views

Odpowiedz

125

Czy lubisz używać private API s? Jeśli tak,

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

Oczywiście nikt nie chce, aby to podczas kierowania AppStore. A bardziej niewiarygodna metoda, a także używa nieudokumentowanych funkcji, ale przejdzie test Apple'a, polega na przechodzeniu przez podobieństwa w poszukiwaniu odpowiedniego elementu przycisku.

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 jest wskaźnik do elementu paska w tablicy .items, po usunięciu wszystkich elementów puste. Ten kod zakłada, że ​​przyciski są ułożone w porządku rosnącym, co nie musi być. Bardziej niezawodna metoda polega na zwiększeniu wartościsortowania o wartości . Oczywiście to nadal zakłada element przycisku paska musi dziedziczyć klasę UIControl i są bezpośrednio subviewsami paska narzędzi/nav-bar, które znowu mogą nie być.


Jak widać, istnieje wiele wątpliwości związanych z nieudokumentowanymi funkcjami. Chcesz jednak wyskoczyć coś pod palcem, prawda? UIBarButtonItem na .action może być selektor formularza:

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

Uwaga wydarzenie argumentem - można uzyskać pozycję kontakcie z

[[event.allTouches anyObject] locationInView:theWindow] 

lub przycisk widoku z

[[event.allTouches anyObject] view] 

Dlatego nie ma potrzeby powtarzania subviews ani używania nieudokumentowanych funkcji do tego, co chcesz zrobić.

+5

I zapomniał o parametr zdarzenia. To oczywiście najlepszy wybór. – progrmr

+1

Parametr zdarzenia ftw. Wielkie dzięki. –

+0

Niezły. Dzięki! – Kalle

1

Można go uzyskać z widoku UINavigationBar. Pasek nawigacji to UIView, który ma 2 lub 3 niestandardowe subviews dla części na pasku.

Jeśli wiesz, że element UIBarButtonItem jest aktualnie wyświetlany na pasku po prawej stronie, możesz pobrać jego ramkę z tablicy podsumowań navbara.

Najpierw potrzebujesz navigationBar, który możesz pobrać z navigationController, który możesz pobrać z UIViewController. Następnie znajdź odpowiednie najbardziej wyszczególnione:

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 

Nie skompilowałem tego kodu, więc YMMV.

8

W systemie iOS 3.2 istnieje znacznie łatwiejszy sposób na pokazanie okna pop-upów z przycisku paska narzędzi.Po prostu zrobić coś takiego:

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

Działa to tylko na iPadzie. –

4

Jest to realizacja używam dla mojego projektu 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

Niestety, to przynajmniej czasami nie działa. Mam programowo utworzone UIBarButtonItems i widzę, że gdy customView jest ustawiona na zero, a następnie na zero, elementy przycisku paska znikają i zawiesza się [parentView.subviews objectAtIndex: indexOfView] (indexOfView nie mniej niż subviews.count). – 18446744073709551615

+0

To nie działa dla mnie – Bogdan

+0

Edytowałem odpowiedź z bieżącą (i roboczą) implementacją –

2

udało mi się dostać Wernera Altewischer za WEpopover pracę przekazując się pasek wraz z
UIBarButton: mod w 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

Zanim zaimplementujesz ten kod, upewnij się, że zadzwoniłeś pod numer [window makeKeyAndVisible] w swoim formularzu delegata aplikacyjnego 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; 
} 
} 
+0

Instancje 'UIBarButtonItem' nie mają właściwości' bounds'. –

+0

Kod nie ma dostępu do granic elementu barButtonItem. Uzyskuje dostęp do granic niestandardowego widoku wewnątrz elementu barButtonItem. –

16

nie widzę tej opcji zamieszczonych (co moim zdaniem jest o wiele prostsze), więc tutaj jest:

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

To nie jest dobre rozwiązanie, ponieważ korzysta z prywatnego interfejsu Apple API. –

+0

valueForKey: jest jedyną używaną metodą. To nie jest prywatne API. Wszystko, co tu robimy, polega na tym, aby założyć, że wdrożenie Apple, którego Apple nie gwarantuje, pozostanie niezmienione. – Gerard

+0

@Gerard "view" to prywatne API tutaj. – bugloaf

-1

I obchodzić go w następujący sposób:

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

Używa prywatnego interfejsu API, więc nie jest dobrym rozwiązaniem. –

+0

"-valueForKey: jest udokumentowaną, publiczną metodą: interfejs KVC API umożliwia zapobieganie bezpośredniemu dostępowi do zmiennej instancji, więc jeśli wartość jest dostępna, żadna czynność nie została podjęta w celu zablokowania dostępu. Jedną z obaw może być trafienie na niezdefiniowaną wartość w przyszłej wersji systemu iOS. Aby rozwiązać ten problem, możesz umieścić wywołanie w bloku blokowania. Nawet jeśli uważasz, że nie możesz go użyć w aplikacji przeznaczonej dla sklepu App Store, nie oznacza to, że ktoś kierowanie na urządzenia z jailbreakiem nie może korzystać z tego podejścia w ich aplikacji. "napisany przez użytkownika @ jeremy-w-sherman w innym poście. –

2

Dopóki UIBarButtonItem (i UITabBarItem) nie odziedziczy po UIView - z powodów historycznych UIBarItem dziedziczy po NSObject - to szaleństwo trwa (od tego czasu pisanie, iOS 8.2 i liczenie ...)

Najlepsza odpowiedź w tym wątku to oczywiście @KennyTM's. Nie bądź głupi i użyj prywatnego API, aby znaleźć widok.

Oto oneline Swift rozwiązanie, aby uzyskać origin.x posortowanej tablicy (jak sugeruje 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) 
    }) 

tablica jest teraz origin.x klasyfikowane z UIBarButtonItem ramek.

(Jeśli czujesz potrzebę, aby dowiedzieć się więcej o zmaganiach cudzych z UIBarButtonItem, polecam Ash Furrow's blogu z 2012 roku: Exploring UIBarButtonItem)

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

To nie jest najlepszym rozwiązaniem i od pewnego punktu widzenia jest to nie dobre rozwiązanie i nie możemy tego zrobić, bo jak obserwacji mamy dostęp do obiektu wewnątrz UIBarBattonItem niejawnie, ale można spróbować zrobić coś takiego:

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

w wyniku i got obok:

punkt 289 {22}

enter image description here

+0

Użycie parametru zdarzenia z akcji dotknięcia jest nadal najbezpieczniejszym sposobem pobrania klatki, gdy nastąpiło dotknięcie. Ale jeśli potrzebujesz wykombinować ramkę bez wykrycia kranów, powiedziałbym, że jest to dobre rozwiązanie ** jeśli ** sprawdzasz rightBarButtonItem dla respondsToSelector. – leolobato

+0

Dziękuję, dobry punkt – gbk

Powiązane problemy