2011-07-28 17 views
7

Tengo una vista de anotación personalizada en el mapa, que tiene UIButton, pero UIButton no responde cuando se presiona. Tengo dos problemas principales con la interacción del usuario en la vista de anotación:Colocando UIButton y otros objetos de UIControl dentro de MKAnnotationView y permitiendo la interacción del usuario

  1. Los botones y otros controles no responden.
  2. Quiero que la anotación bloquee los toques de acuerdo con mi implementación de - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event, es decir, si devuelvo SÍ, no quiero que me envíen los toques al MKMapView (posiblemente seleccionando otras anotaciones que están DETRÁS de mi vista de anotación) , Quiero manejar el toque yo mismo en este caso.

Me he asegurado userInteractionEnabled se establece en YES y me han investigado cómo los toques se envían a la vista de anotación personalizada (mi subclase de MKAnnotationView) reemplazando touchesBegan etc - pero parece que los toques son generalmente cancelados (pensé que había logrado obtener touchesEnded varias veces), por lo que parece que incluso será difícil implementar manualmente cualquier interacción del usuario con la vista de anotación personalizada.

¿Alguien tiene alguna idea de permitir una mayor interacción del usuario con los objetos MKAnnotationView?

+0

¿Es capaz de escribir algo de código en cuanto a cómo está agregando sus UIControls a MKAnnotationView? – Ricky

+1

es mejor poner botones en la llamada, no la anotación –

+0

@Pennypacker Tengo una vista UV con los controles anidados en su interior, esta UIView también se usa en otra parte de la aplicación. UIView se agrega a mi vista de anotación personalizada. – jhabbott

Respuesta

5

Pude resolver esto con la ayuda de un colega. La solución es anular - (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event. Nuestra suposición es que MKAnnotationView (del cual su vista de anotación debe heredar) anula esto para hacer lo 'incorrecto' (presumiblemente para que la selección de anotación no se bloquee entre anotaciones superpuestas). Por lo tanto, tiene que volver a anularlo para hacer lo correcto y devolver el UIView apropiado, el sistema le enviará los eventos y el usuario podrá interactuar con él :). Esto tiene el efecto secundario beneficioso (en este caso) que la anotación interactiva bloquea la selección de anotaciones que están detrás de ella.

+0

Todavía estoy tratando de averiguar cómo implementarlo yo mismo ... ¿Anulas el 'hitTest: withEvent:' dentro de 'MKAnnotationView', o' MKMapView'? Si se trata del 'MKMapView' ¿significa eso que necesito crear una subclase para anular el método? ¿Qué vista necesita devolver, el 'rightCalloutAccessoryView' o el' MKAnnotationView'? – jowie

+1

Subclase 'MKAnnotationView' con su clase de vista personalizada y anule' hitTest: withEvent: '- desde aquí puede devolver la vista, o una de sus subvistas (por ejemplo, un botón u otro objeto interactivo) - se enviarán toques a ese ver. – jhabbott

+0

extrañamente, eso no funciona para mí. Lo único que puedo hacer es implementar 'pointInside: withEvent' y devolver' YES'. Incluso entonces, funciona bien con una anotación de pin normal, pero ninguno de los métodos funciona con la anotación de pin de ubicación del usuario. – jowie

0

Encontré que en lugar de anular hitTest:withEvent: podía simplemente reemplazar pointInside:withEvent: en su lugar y solo obtener que devuelva YES. Supongo que oficialmente debería hacer una comprobación de intersección puntual para asegurarme de que el lugar en el que estoy tocando está dentro del elemento de control, pero en la práctica, simplemente poner return YES parece funcionar perfectamente bien, permitiéndote descartar el MKAnnotationView tocando lejos de eso.

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    // for testing purposes 
    BOOL result = [super pointInside:point withEvent:event]; 
    NSLog(@"pointInside:RESULT = %i", result); 

    return YES; 
} 
+0

Si solo reemplaza pointInside: withEvent, entonces cualquier otra anotación * detrás de * su anotación interactiva aún se puede seleccionar, por lo tanto se desactivará la activa. Deberá anular hitTest: withEvent para bloquear los toques que se envían a otras anotaciones superpuestas (es decir, detrás). – jhabbott

+0

Entonces, cuando sobrescribe 'pointInside: withEvent:', ¿devuelve nil para bloquear el burbujeo? – jowie

+0

No, supongo que por 'burbujeo' te refieres a la aparición del rótulo? Mi pregunta/solución es para cuando no estés usando textos destacados (porque no son muy personalizables) y en su lugar utilizas anotaciones personalizadas (agregando la anotación personalizada cuando se selecciona una de tus otras anotaciones 'pin'). – jhabbott

0

Agregando a la respuesta de jhabbott, esto es lo que funcionó para mí. Tengo una vista de anotación personalizada MKCustomAnnotationView que contiene una anotación personalizada CustomPin como anotación. Ese 'pin' tiene un UIButton como reemplazo de botón de accesorio que quería obtener eventos táctiles.

Mi método hitTest se vería así:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    UIView *result = [super hitTest:point withEvent:event]; 
    //NSLog(@"ht: %f:%f %d %@", point.x, point.y, [[event touchesForView:self] count], result); 

    if ([result isKindOfClass:[MKCustomAnnotationView class]]) 
    { 
     MKCustomAnnotationView *av = (MKCustomAnnotationView *)result; 
     CustomPin *p = av.annotation; 
     UIButton *ab = p.accessoryButton; 
     if (p.calloutActive && point.x >= ab.frame.origin.x) 
      return ab; 
    } 

    return result; 
} 

El bool calloutActive probablemente no es necesario en la mayoría de los casos.

0

Para todos aquellos que buscan agregar un tapGesture a una subvista AnnotationView entonces la respuesta en la parte inferior de esta:

MKannotationView with UIButton as subview, button don't respond

trabajado para mí:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    if (CGRectContainsPoint(_button.frame, point)) { 
     return _button; 
    } 
    return [super hitTest:point withEvent:event]; 
} 
Cuestiones relacionadas