web-dev-qa-db-fra.com

Déterminez le cadre UIBarButtonItem dans la fenêtre?

UIBarButtonItem n'étend pas UIView, il n'y a donc rien de tel qu'une propriété de cadre.

Mais est-ce que je peux obtenir quel est son cadre CGRect par rapport à l'application UIWindow?

62
leolobato

Aimez-vous utiliser API privée s? Si oui,

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

Bien sûr, personne ne le souhaite pour cibler l'AppStore. Une méthode plus peu fiable, qui utilise également des fonctionnalités non documentées, mais passera le test d'Apple, consiste à parcourir les sous-vues pour rechercher l'élément de bouton correspondant. 

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

La index est l'index de votre élément de barre dans le tableau de .items, après la suppression de tous les éléments vides. Ceci suppose les boutons sont disposés en ordre croissant, ce qui peut ne pas être le cas. Une méthode plus fiable consiste à trier le tableau buttons en augmentant la valeur .Origin.x. Bien sûr, cela toujours suppose l'élément de bouton de la barre doit hériter de la classe UIControl et constituent des sous-vues directes de la barre d'outils/barre de navigation, qui peuvent ne pas l'être à nouveau. 


Comme vous pouvez le constater, il y a beaucoup d'incertitude à propos des fonctionnalités non documentées. Cependant, vous voulez juste faire apparaître quelque chose sous le doigt, n'est-ce pas? Le .action de UIBarButtonItem peut être un sélecteur de la forme:

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

notez l'argument event - vous pouvez obtenir la position de contact avec

[[event.allTouches anyObject] locationInView:theWindow]

ou la vue des boutons avec

[[event.allTouches anyObject] view]

Par conséquent, il n'est pas nécessaire d'itérer les sous-vues ou d'utiliser des fonctionnalités non documentées pour ce que vous voulez faire.

125
kennytm

Je n'ai pas vu cette option affichée (ce qui à mon avis est beaucoup plus simple), alors la voici:

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

Dans iOS 3.2, il existe un moyen beaucoup plus simple d’afficher une feuille d’action dans une barre d’outils. Faites simplement quelque chose comme ça:

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

Voici l'implémentation que j'utilise pour mon projet 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
4
-(CGRect) getBarItemRc :(UIBarButtonItem *)item{
    UIView *view = [item valueForKey:@"view"];
    return [view frame];
}
2
Gank

Tant que UIBarButtonItem (et UITabBarItem) n'hérite pas de UIView - pour des raisons historiques, UIBarItem hérite de NSObject - cette folie continue (à l'heure actuelle, iOS 8.2 et en comptant ...)

La meilleure réponse dans ce fil est évidemment @ KennyTM . Ne soyez pas stupide et utilisez l'API privée pour trouver la vue.

Voici une solution Swift sur ligne pour obtenir un tableau trié par Origin.x (comme la réponse de Kenny suggère):

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

Le tableau est maintenant Origin.x trié avec les cadres UIBarButtonItem.

(Si vous ressentez le besoin d'en savoir plus sur les luttes d'autres personnes avec UIBarButtonItem, je recommande Ash Furrow's billet de blog datant de 2012: Exploration de UIBarButtonItem )

2
Erik Tjernlund

J'ai réussi à faire fonctionner WEpopover de Werner Altewischer en passant la barre d'outils en même temps que la
UIBarButton: Mod est dans 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];
}
2
Jim Malak

Vous pouvez l'obtenir à partir de la vue UINavigationBar. La barre de navigation est une UIView qui a 2 ou 3 vues sous-vues personnalisées pour les pièces de la barre. 

Si vous savez que UIBarButtonItem est actuellement affiché dans la barre de navigation de droite, vous pouvez obtenir son cadre dans le tableau des sous-vues de la barre de navigation. 

Vous avez d’abord besoin de la barre navigationBar que vous pouvez obtenir à partir du contrôleur navigationContrôleur que vous pouvez obtenir à partir de UIViewController. Ensuite, trouvez la sous-vue la plus à droite:

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

Je n'ai pas compilé ce code, donc YMMV.

1
progrmr

Ce n'est pas la meilleure solution et, d'un certain point de vue, ce n'est pas la bonne solution et nous ne pouvons pas faire comme suit parce que nous accédons implicitement à l'objet dans UIBarBattonItem, mais vous pouvez essayer de faire quelque chose comme:

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

comme résultat je suis le suivant:

point {289, 22}

 enter image description here

0
gbk