13

Quiero agregar funcionalidad a mis botones de retroceso a través de mi aplicación UINavigationController donde presionar prolongadamente el botón Atrás se abrirá en la raíz. Sin embargo, no puedo averiguar dónde adjuntar el reconocedor de gestos. ¿Subclono UINavigationBar e intento detectar si la pulsación larga está en la región del botón izquierdo?detectar pulsación larga en el botón Atrás de UINavigationItem

He oído hablar de personas que añaden una funcionalidad similar anteriormente. ¿Alguien tiene alguna idea?

Respuesta

6

Creo que UIGestureRecognizers solo se puede agregar a UIViews y subclases de UIViews.

http://developer.apple.com/library/ios/#documentation/uikit/reference/UIView_Class/UIView/UIView.html

El botón de retroceso es una UIBarButtonItem que desciende desde NSObject. Por lo tanto, usted no será capaz de conectar un reconocedor gesto a un botón de retroceso estándar utilizando

UILongPressGestureRecognizer *longPressGesture = 
      [[[UILongPressGestureRecognizer alloc] 
       initWithTarget:self action:@selector(longPress:)] autorelease]; 

[self.navigationItem.backBarButtonItem addGestureRecognizer:longPressGesture]; 

Sin embargo, puede agregar una vista personalizada a un UIBarButtonItem. Una vista personalizada podría ser tan fácilmente un UIView, UIButton, UILabel, etc.

Ejemplo:

UIView *myTransparentGestureView = [[UIView alloc] initWithFrame:CGRectMake(0,0,40,30)]; 
[myTransparentGestureView addGestureRecognizer:longPressGesture]; 
[self.navigationItem.backBarButtonItem setCustomView:myTransparentGestureView]; 
// Or you could set it like this 
// self.navigationItem.backBarButtonItem.customView = myTransparentGestureView; 
[myTransparentGestureView release]; 

Hay que tener cuidado, sin embargo, ya que el establecimiento de propiedades en backBarButtonItem se aplica a la siguiente vista que se presiona . Entonces, si tiene la vista A que presiona para ver B y desea que se reconozca el gesto cuando toca en la vista B. Debe configurarlo en la vista A.

+0

Adición de un reconocedor gesto a una vista personalizada en el backButtomItem didn No funciona para mí ... el reconocedor se niega a disparar. ¿Pudiste hacerlo funcionar con el código de arriba? – kevboh

+0

Es probable que no funcione porque el backBarButtonItem es de solo lectura, por lo que no acepta una vista personalizada.Lo más probable es que necesites crear tu propio elemento de barra izquierda como esta respuesta. http://stackoverflow.com/questions/526520/how-to-create-backbarbuttomitem-with-custom-view-for-a-uinavigationcontroller – Andrew

+0

Ah, pero luego pierdo mi flecha trasera a menos que encuentre una imagen ... probablemente no vale la pena. ¡Gracias de todos modos! – kevboh

15

Sé que esta pregunta es antigua, pero vine con una solución En lugar de intentar agregar el reconocedor de gestos al botón en sí (lo que sería ideal), lo agregué al self.navigationController.navigationBar y luego en el método de acción, uso el locationInView para ver si estoy sobre el botón Atrás. No estaba del todo seguro acerca de cómo identificar el botón Atrás, así que torpemente acabo de tomar la primera subvista con una coordenada X menor que algún valor arbitrario, pero parece prometedor. Si alguien tiene una mejor manera de identificar el marco del botón Atrás, házmelo saber.

- (void)longPress:(UILongPressGestureRecognizer *)sender 
{ 
    if (sender.state == UIGestureRecognizerStateEnded) 
    { 
     // set a default rectangle in case we don't find the back button for some reason 

     CGRect rect = CGRectMake(0, 0, 100, 40); 

     // iterate through the subviews looking for something that looks like it might be the right location to be the back button 

     for (UIView *subview in self.navigationController.navigationBar.subviews) 
     { 
      if (subview.frame.origin.x < 30) 
      { 
       rect = subview.frame; 
       break; 
      } 
     } 

     // ok, let's get the point of the long press 

     CGPoint longPressPoint = [sender locationInView:self.navigationController.navigationBar]; 

     // if the long press point in the rectangle then do whatever 

     if (CGRectContainsPoint(rect, longPressPoint)) 
      [self doWhatever]; 
    } 
} 

- (void)addLongPressGesture 
{ 
    if (NSClassFromString(@"UILongPressGestureRecognizer")) 
    { 
     UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)]; 
     [self.navigationController.navigationBar addGestureRecognizer:longPress]; 
     [longPress release]; 
    } 
} 
+0

idea genial. La próxima vez que necesite hacer esto, trataré de acercarte. ¡Gracias por el seguimiento! – kevboh

+0

Estoy bien con cualquier presión larga allí para estallar, me parece razonable. –

+0

Tenía el mismo requisito que configurar un gesto de vista larga en el botón Atrás. El problema con este enfoque es que el botón Atrás no permanece en estado resaltado. Así que configuré la propiedad cancelsTouchesInView en NO.BUt, entonces mi manejador longPressHandler y backButton se llama. ¿Alguna solución para esto? – user1010819

3

Seguí un camino ligeramente diferente, pensé que lo compartiría. Las respuestas anteriores están muy bien, pero en realidad, si el tiempo prensa está en el principal 1/3 de la barra de navegación, que es lo suficientemente bueno para mí:

- (void)longPress:(UILongPressGestureRecognizer *)gr 
{ 
    NSLog(@"longPress:"); 
    UINavigationBar *navBar = [self navigationBar]; 
    CGFloat height = navBar.bounds.size.height; 
    CGPoint pt = [gr locationOfTouch:0 inView:navBar]; 
    //NSLog(@"PT=%@ height=%f", NSStringFromCGPoint(pt), height); 
    if(CGRectContainsPoint(CGRectMake(0,0,100,height), pt)) { 
     [self popToViewController:self.viewControllers[0] animated:YES]; 
    } 
} 
0

aquí está mi solución:

En AppDelegate (la "propietario" de la barra de navegación en mi aplicación), en applicationDidFinishLaunchingWithOptions:

obtener la vista barra de navegación y añadir el reconocedor gesto a la visión de conjunto:

// Get the nav bar view 
UINavigationBar *myNavBar = nil; 
for (UIView *view in [self.window.rootViewController.view subviews]) { 
    if ([view isKindOfClass:[UINavigationBar class]]) { 
     NSLog(@"Found Nav Bar!!!"); 
     myNavBar = (UINavigationBar *)view; 
    } 
} 

UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self 
                         action:@selector(backButtonLongPress:)]; 
[myNavBar addGestureRecognizer:longPress]; 
NSLog(@"Gesture Recognizer Added."); 

Luego, en appDel egate, en - (void) backButtonLongPress: (id) emisor

Compruebe si el gesto se produce dentro del marco del botón de retroceso:

if ([sender state] == UIGestureRecognizerStateBegan) { 

    // Get the nav bar view 
    UINavigationBar *myNavBar = nil; 
    for (UIView *view in [self.window.rootViewController.view subviews]) { 
     if ([view isKindOfClass:[UINavigationBar class]]) { 
      NSLog(@"Found Nav Bar!!!"); 
      myNavBar = (UINavigationBar *)view; 
     } 
    } 

    // Get the back button view 
    UIView *backButtonView = nil; 
    for (UIView *view in [myNavBar subviews]) { 
     if ([[[view class] description] isEqualToString:@"UINavigationItemButtonView"]) { 
      backButtonView = view; 
      NSLog(@"Found It: %@", backButtonView); 
      NSLog(@"Back Button View Frame: %f, %f; %f, %f", backButtonView.frame.origin.x, backButtonView.frame.origin.y, backButtonView.frame.size.width, backButtonView.frame.size.height); 
     } 
    } 

    CGPoint longPressPoint = [sender locationInView:myNavBar]; 
    NSLog(@"Touch is in back button: %@", CGRectContainsPoint(backButtonView.frame, longPressPoint) ? @"YES" : @"NO"); 
    if (CGRectContainsPoint(backButtonView.frame, longPressPoint)) { 
     // Place your action here 
    } 

    // Do nothing if outside the back button frame 

} 
Cuestiones relacionadas