2010-01-16 5 views
20

Je souhaite déclencher un événement au toucher lorsqu'un utilisateur appuie sur le titre de la barre de navigation de l'une de mes vues.UINavigationBar Touch

Je n'arrive pas à savoir si je peux accéder à la vue du titre de l'UINavigationBar pour y connecter un événement tactile.

Est-ce encore possible?

Répondre

30

La solution que je trouve est un bouton, j'utiliser ce qui suit (mais je ne sais pas comment « juridique » est):

UIButton *titleLabelButton = [UIButton buttonWithType:UIButtonTypeCustom]; 
[titleLabelButton setTitle:@"myTitle" forState:UIControlStateNormal]; 
titleLabelButton.frame = CGRectMake(0, 0, 70, 44); 
titleLabelButton.font = [UIFont boldSystemFontOfSize:16]; 
[titleLabelButton addTarget:self action:@selector(didTapTitleView:) forControlEvents:UIControlEventTouchUpInside]; 
self.navigationItem.titleView = titleLabelButton; 

Mettez ce morceau de code où que vous définissez votre titre. Puis ailleurs, j'ai eu cela à tester:

- (IBAction)didTapTitleView:(id) sender 
{ 
    NSLog(@"Title tap"); 
} 

qui a enregistré "Title tap" sur la console!

La façon dont je suis allé à ce sujet peut être complètement faux, mais pourrait vous donner une idée de ce que vous pouvez regarder. Cela m'a certainement aidé! Il y a probablement une meilleure façon de le faire.

+1

Bien qu'il se dirige dans la bonne direction, c'est plutôt moche - la propriété de police de UIButton est obsolète, et même avec cette propriété, le texte du titre est très différent de la normale. Pourquoi s'embêter avec un bouton? Un UIView clair fonctionnerait mieux. –

+0

Rien à reprocher à UILabel. Assurez-vous simplement, vous définissez le label.userInteractionEnabled = YES. Sinon, l'étiquette ne réagira pas aux événements tactiles. – JapCon

9

La référence de classe UINavigationItem possède une propriété titleView, que vous pouvez définir comme suit: UIView. En d'autres termes, créez une sous-classe UIView avec vos gestionnaires tactiles, puis, lorsque vous poussez votre élément de navigation, définissez la propriété titleView de cet élément sur une instance de votre sous-classe.

+0

Merci, mais comment puis-je agir sur ce contact, par exemple - comment puis-je appeler une méthode dans mon contrôleur de vue globale si le titleView est touché? – mootymoots

+0

En outre, avec cette approche, mon attribut title est perdu. Pourriez-vous expliquer plus loin? J'ai ajouté un gestionnaire touchesBegan avec un simple NSLog (@ "touché"); mais il ne fait rien quand titleView est frappé. Je crée une instance de la sous-classe et l'affecte à l'instance de la vue que je suis sur le point de pousser, c'est-à-dire view.navigationItem.titleView = mySubclass; – mootymoots

+0

Votre UIView personnalisé peut avoir de nombreuses propriétés, y compris un UILabel pour remplacer le titre, et une propriété UIViewController pour le contrôleur de vue «parent», que vous définissez lorsque vous créez une instance de votre vue personnalisée. Vérifiez également que votre vue possède un cadre de taille suffisante. –

42

Vous pouvez ajouter un outil de reconnaissance de gestes pour appuyer d'une seule pression sur le titre du contrôleur de navigation. Je trouve que dans les sous-vues navigationBar, le titre est celui à l'index 1, l'index du bouton gauche est 0 et l'index du bouton droit est 2.

UITapGestureRecognizer *navSingleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(navSingleTap)]; 
navSingleTap.numberOfTapsRequired = 1; 
[[self.navigationController.navigationBar.subviews objectAtIndex:1] setUserInteractionEnabled:YES]; 
[[self.navigationController.navigationBar.subviews objectAtIndex:1] addGestureRecognizer:navSingleTap]; 

puis mettre en œuvre ce qui suit quelque part dans votre mise en œuvre.

-(void)navSingleTap 

Vous pouvez donc l'utiliser pour un seul appui, ou vous pouvez implémenter n'importe quel outil de reconnaissance de gestes souhaité sur ce titre.

+0

Cela fonctionne si vous ne voulez pas définir un titleView personnalisé. (Ce que je n'ai pas fait.) – zekel

+0

Est-il possible de définir une couleur de teinte afin qu'elle ressemble un peu plus à un bouton? J'ai essayé 'setTintColor' et' setTintAdjustmentMode', mais aucun ne fonctionne –

+0

Cela semble définitivement être la réponse la plus valable. Merci ~ – James

25

Aucune des autres réponses n'a bien fonctionné pour moi. Plutôt que d'ajouter un geste à une sous-vue existante du navigationBar, ou remplacer le titleview, j'ai simplement ajouté un UIView clair couvrant une bonne partie de la navigationBar ...

- (void) setupNavbarGestureRecognizer { 
    // recognise taps on navigation bar to hide 
    UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(showHideNavbar)]; 
    gestureRecognizer.numberOfTapsRequired = 1; 
    // create a view which covers most of the tap bar to 
    // manage the gestures - if we use the navigation bar 
    // it interferes with the nav buttons 
    CGRect frame = CGRectMake(self.view.frame.size.width/4, 0, self.view.frame.size.width/2, 44); 
    UIView *navBarTapView = [[UIView alloc] initWithFrame:frame]; 
    [self.navigationController.navigationBar addSubview:navBarTapView]; 
    navBarTapView.backgroundColor = [UIColor clearColor]; 
    [navBarTapView setUserInteractionEnabled:YES]; 
    [navBarTapView addGestureRecognizer:gestureRecognizer]; 
} 
+0

c'est le seul qui a fonctionné pour moi jusqu'à présent, bien que j'ai semblé devoir ajouter: [self.navigationController.navigationBar setUserInteractionEnabled: YES]; et j'ai toujours une interférence avec les boutons en raison des noms de boutons variables dans le reste de mon application - avec une manière cohérente d'attacher juste touchability au titre (qui dans mon cas est un UIImageView) –

+1

aha, j'ai finalement obtenu juste le titre étant touchable - voici comment: http://pastebin.com/eFwTShhz –

+0

@SamJoseph vous devriez poster cette solution comme une réponse –

1

Je ne voulais pas spécifier un bouton comme une coutume titleView parce que cela signifierait que je ne peux plus utiliser le titre standard. D'un autre côté, lorsque vous ajoutez un outil de reconnaissance de gestes à la barre de navigation, nous devons nous assurer qu'il ne se déclenche pas lorsque vous tapez sur un bouton.

Cette solution réalise à la fois (à ajouter à une sous-classe UINavigationBar):

- (void)awakeFromNib { 
    // put in -initWithFrame: if initialized manually 
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(ft_titleTapped:)]; 
    [self addGestureRecognizer:tap]; 
} 

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { 
    UIView *titleView = [self valueForKey:@"titleView"]; 
    CGRect titleFrame = titleView.frame; 
    titleFrame.origin.y = 0; // expand to full height of navBar 
    titleFrame.size.height = self.frame.size.height; 
    return CGRectContainsPoint(titleFrame, [gestureRecognizer locationInView:self]); 
} 

- (void)ft_titleTapped:(UITapGestureRecognizer*)sender { 
    if (sender.state == UIGestureRecognizerStateEnded) { 
     // could add some checks here that the delegate is indeed a navigation controller 
     UIViewController<FTViewControllerAdditions> *viewController = (id)[((UINavigationController*)self.delegate) topViewController]; 
     if ([viewController respondsToSelector:@selector(titleViewTapped:)]) { 
      [viewController titleViewTapped:self]; 
     } 
    } 
} 

Il envoie automatiquement un message -titleViewTapped: au contrôleur de vue (si elles sont appliquées).Dans une sous-classe UITableViewController vous pouvez mettre en œuvre la méthode comme celui-ci pour un défilement à fonction supérieure:

- (void)titleViewTapped:(id)sender { 
    [self.tableView setContentOffset:CGPointMake(0, -self.tableView.contentInset.top) animated:YES]; 
} 

Attention: nous récupérons la vue du titre en utilisant la -valueForKey:@"titleView" sans papier. Techniquement, il n'utilise pas une API privée, mais pourrait échouer dans une future version d'iOS!

+0

Cette réponse a fonctionné pour moi en remplaçant '- [gestureRecognizerShouldBegin]' dans une catégorie sur UINavigationBar et en important cette catégorie dans mon contrôleur de vue. –

1

L'une des options possibles: (utilisation UILabel)

UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doSomething:)]; 
UILabel * titleView = [UILabel new]; 
titleView.text = @"Test"; 
[titleView sizeToFit]; 
titleView.userInteractionEnabled = YES; 
[titleView addGestureRecognizer:tapGesture]; 

self.navigationItem.titleView = titleView; 
0

Cela peut être fait en attachant un UITapGestureRecognizer à la barre de navigation sous-vue qui correspond à la titleview. Comme l'index de titleView varie en fonction du nombre d'éléments de bouton de barre, il est nécessaire de parcourir toutes les sous-vues de la barre de navigation pour trouver la vue correcte.

import UIKit 

class ViewController: UIViewController { 

    override func viewDidLoad() { 
    super.viewDidLoad() 

    addTitleViewTapAction("tapped", numberOfTapsRequired: 3) 
    } 

    func addTitleViewTapAction(action: Selector, numberOfTapsRequired: Int) { 

    if let subviews = self.navigationController?.navigationBar.subviews { 
     for subview in subviews { 
     // the label title is a subview of UINavigationItemView 
     if let _ = subview.subviews.first as? UILabel { 
      let gesture = UITapGestureRecognizer(target: self, action: action) 
      gesture.numberOfTapsRequired = numberOfTapsRequired 
      subview.userInteractionEnabled = true 
      subview.addGestureRecognizer(gesture) 
      break 
     } 
     } 
    } 
    } 

    @objc func tapped() { 

    print("secret tap") 
    } 
} 
2

C'est la plus simple et la plus simple solution à Swift, il suffit de copier/coller et remplir les espaces vides:

let navTapGesture = UITapGestureRecognizer(target: <#T##AnyObject?#>, action: <#T##Selector#>) 
navigationItem.titleView.userInteractionEnabled = true 
navigationItem.titleView.addGestureRecognizer(navTapGesture) 

Assurez-vous de régler le userInteractionEnabled à true sur le titleView, son désactivé par défaut .