2010-01-16 31 views
20

Me gustaría disparar un evento en el tacto cuando un usuario toca el título de la barra de navegación de una de mis vistas.UINavigationBar Touch

No sé si puedo acceder a la vista del título de UINavigationBar para conectarlo a un evento táctil.

¿Esto es posible?

Respuesta

30

La solución que he encontrado es un botón, que utilice el siguiente (pero no sé cómo "legal" es):

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; 

poner ese trozo de código que cada vez que configura su título. Luego en otro lugar tuve esto para probar:

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

que registraba "Título tap" en la consola!

La forma en que he trabajado sobre esto puede ser completamente incorrecta, pero podría darte una idea de lo que puedes mirar. ¡Sin duda me ayudó! Sin embargo, es probable que haya una mejor manera de hacerlo.

+1

Aunque está yendo en la dirección correcta, esto es bastante feo: la propiedad de fuente de UIButton está en desuso, e incluso con esa propiedad, el texto del título se ve muy diferente de lo normal. ¿Por qué molestarse con un botón? Una UIView clara funcionaría mejor. –

+0

Nada malo con UILabel. Solo asegúrate de configurar el label.userInteractionEnabled = YES. De lo contrario, la etiqueta no reaccionará con los eventos táctiles. – JapCon

9

La referencia de clase UINavigationItem tiene una propiedad titleView, que puede establecer en su personalizada UIView.

En otras palabras, cree una subclase de UIView con sus controladores táctiles y luego, cuando presione el elemento de navegación, establezca la propiedad titleView de ese elemento en una instancia de su subclase.

+0

Gracias, pero ¿cómo actúo con ese toque, por ejemplo, cómo puedo llamar a un método en mi controlador de vista general si se toca el titleView? – mootymoots

+0

Además, con este enfoque, mi atributo de título se pierde. ¿Podrías explicar más? He agregado un controlador touchesBegan con un simple NSLog (@ "tocado"); pero no hace nada cuando se golpea titleView. Estoy creando una instancia de la subclase y asignándola a la instancia de la vista que estoy a punto de enviar, es decir, view.navigationItem.titleView = mySubclass; – mootymoots

+0

Su 'UIView' personalizada puede tener muchas propiedades, incluyendo un' UILabel' para reemplazar el título, y una propiedad 'UIViewController' para el controlador de vista" principal ", que usted configura cuando crea una instancia de su vista personalizada. También verifique que su vista tenga un marco de tamaño suficiente. –

42

Puede agregar un reconocedor de gestos para que sea un simple toque al título del controlador de navegación. He encontrado que en los subvistas navigationbar, el título es el que está en el índice 1, el índice del botón izquierdo es 0 y el índice del botón derecho es 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]; 

y luego aplicar el siguiente en algún lugar de su aplicación.

-(void)navSingleTap 

Para que pueda usar esto para un solo toque, o puede implementar cualquier reconocedor de gestos que desee en ese título.

+0

Esto funciona si no desea establecer un titleView personalizado. (Lo cual no hice). – zekel

+0

¿Es posible establecer un color de tinte para que se vea un poco más como un botón? He intentado 'setTintColor' y' setTintAdjustmentMode', pero tampoco funciona –

+0

Esto definitivamente parece ser la respuesta más válida. Gracias ~ – James

25

Ninguna de las otras respuestas funcionó bien para mí. En lugar de añadir un gesto a una vista secundaria existente del navigationbar, o reemplazar el titleview, simplemente agregué un UIView transparente que cubre una buena parte 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

este es el único que también funcionó para mí, aunque parecía necesitar agregar: [self.navigationController.navigationBar setUserInteractionEnabled: YES]; y todavía tengo interés en los botones debido a los nombres de botones variables como parte del resto de mi aplicación, con una forma consistente de adjuntar touchability al título (que en mi caso es un UIImageView) –

+1

aha, finalmente conseguí solo el título es táctil - así es cómo: http://pastebin.com/eFwTShhz –

+0

@SamJoseph debe publicar esa solución como una respuesta –

1

que no desea especificar un botón como una costumbre titleView porque eso significaría que ya no puedo usar el título estándar. Por otro lado, al agregar un reconocedor de gestos de toque a la barra de navegación, debemos asegurarnos de que no se active al tocar un botón de la barra.

Esta solución lleva a cabo tanto (para ser añadido a una subclase 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]; 
     } 
    } 
} 

envía automáticamente un mensaje -titleViewTapped: al controlador de vista (si se aplica).En una subclase UITableViewController se podía poner en práctica el método como este para un desplazamiento a la función de la parte superior:

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

Precaución: estamos recuperando el título de la vista mediante el indocumentado -valueForKey:@"titleView". ¡Técnicamente no usa una API privada, pero aún puede fallar en una futura versión de iOS!

+0

Esta respuesta me funcionó sobrescribiendo '- [gestureRecognizerShouldBegin]' en una categoría en UINavigationBar e importando esa categoría en mi controlador de vista. –

1

Una de las posibles opciones: (Usar 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

Esto se puede hacer uniendo una subvista UITapGestureRecognizer a la barra de navegación que corresponde a la titleview.

Como el índice de titleView varía según la cantidad de elementos del botón de barra que haya, es necesario recorrer todas las subvistas de la barra de navegación para encontrar la vista correcta.

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

Ésta es la solución más simple y más fácil en Swift, simplemente copiar/pegar y rellenar los espacios en blanco:

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

Asegúrese de ajustar la userInteractionEnabled a true en el titleView, su desactivada por defecto .