UIBarButtonItem
nie rozszerza się o UIView
, więc nie ma to jak własność ramki.Wyobraź sobie ramkę UIBarButtonItem w oknie?
Ale czy istnieje sposób, w jaki mogę uzyskać to, co to jest ramka CGRect
, w stosunku do aplikacji UIWindow
?
UIBarButtonItem
nie rozszerza się o UIView
, więc nie ma to jak własność ramki.Wyobraź sobie ramkę UIBarButtonItem w oknie?
Ale czy istnieje sposób, w jaki mogę uzyskać to, co to jest ramka CGRect
, w stosunku do aplikacji UIWindow
?
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ć.
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.
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];
}
Działa to tylko na iPadzie. –
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
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
To nie działa dla mnie – Bogdan
Edytowałem odpowiedź z bieżącą (i roboczą) implementacją –
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];
}
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;
}
}
Instancje 'UIBarButtonItem' nie mają właściwości' bounds'. –
Kod nie ma dostępu do granic elementu barButtonItem. Uzyskuje dostęp do granic niestandardowego widoku wewnątrz elementu barButtonItem. –
nie widzę tej opcji zamieszczonych (co moim zdaniem jest o wiele prostsze), więc tutaj jest:
UIView *barButtonView = [barButtonItem valueForKey:@"view"];
To nie jest dobre rozwiązanie, ponieważ korzysta z prywatnego interfejsu Apple API. –
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
@Gerard "view" to prywatne API tutaj. – bugloaf
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
}
Używa prywatnego interfejsu API, więc nie jest dobrym rozwiązaniem. –
"-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. –
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)
-(CGRect) getBarItemRc :(UIBarButtonItem *)item{
UIView *view = [item valueForKey:@"view"];
return [view frame];
}
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}
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
Dziękuję, dobry punkt – gbk
I zapomniał o parametr zdarzenia. To oczywiście najlepszy wybór. – progrmr
Parametr zdarzenia ftw. Wielkie dzięki. –
Niezły. Dzięki! – Kalle