2009-08-15 9 views
6

Decir que tengo este código:¿Cómo hacer que un botón de intercepción de superview toque eventos?

#import <UIKit/UIKit.h> 

@interface MyView : UIView 
@end 
@implementation MyView 

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    // How can I get this to show up even when the button is touched? 
    NSLog(@"%@", [touches anyObject]); 
} 

@end 

@interface TestViewAppDelegate : NSObject <UIApplicationDelegate> 
{ 
    UIWindow *window; 
} 

@end 

@implementation TestViewAppDelegate 

- (void)applicationDidFinishLaunching:(UIApplication *)application 
{ 
    window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 

    MyView *view = [[MyView alloc] initWithFrame:[window frame]]; 
    [view setBackgroundColor:[UIColor whiteColor]]; 

    UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 
    [button setTitle:@"Hiya!" forState:UIControlStateNormal]; 
    [button setFrame:CGRectMake(100.0, 100.0, 200.0, 200.0)]; 
    [view addSubview:button]; 

    [window addSubview:view]; 
    [window makeKeyAndVisible]; 
} 


- (void)dealloc 
{ 
    [window release]; 
    [super dealloc]; 
} 

@end 

¿Hay alguna manera de interceptar los eventos de toque enviadas a su botón? Lo que me gustaría hacer finalmente es crear una subclase UIView que diga a su controlador de vista (o delegar, lo que sea) cuando detecte un deslizamiento para poder "empujar" el siguiente controlador de vista a la pila (similar a la pantalla de inicio del iPhone) Pensé que este era el primer paso, pero estoy abierto a sugerencias si me estoy acercando a esto incorrectamente.

Respuesta

1

Gracias por las sugerencias y respuestas informativas. Terminé simplemente usando la explicación que se muestra en la página this: (en "Trick 1: Emulación de aplicaciones de fotos deslizando/acercando/desplazando con un solo UIScrollView").

16

estaría interesado en ver otras soluciones, pero la manera más fácil que conozco es para anular cualquiera de estos métodos: dos UIView

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event; 
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event; 

Estos métodos serán llamadas para determinar si el contacto está dentro del límites de la vista o cualquiera de sus subvistas, por lo que este es un buen punto para interceptar el toque y luego pasarlo. Sólo haz lo que quieras, y luego

return [super hitTest:point withEvent:event]; 

o

return [super pointInside:point withEvent:event]; 
+0

no te refieres a return [superview hitTest: point withEvent: event]; –

+0

'super' es correcto porque querrá llamar al método de clases clase principal,' superview' omitirá esto. – keegan3d

0

creo que tendría que subclase UIButton en este caso y anular las respuestas a eventos táctiles y de movimiento de UIResponder. Luego, puede reenviarlos a cualquier objeto que desee para asumir que la subclase UIButton podría llegar a él.

En este caso, los pasaría a la super visión de UIButton.

@interface MyButton : UIButton 
@end 

@implementation MyButton 

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    [[self superview] touchesMoved:touches withEvent:event]; 
} 

@end 

Ver UIResponder documentation

+1

UIButton es un clúster de clase, desafortunadamente. Esto significa que es casi imposible subclasificar. –

+0

No sabía que era tan malo. Mencionó solo una subclase de UIView, así que solo estaba usando UIButton ya que lo usó en su código de ejemplo. – criscokid

4

instinto diría "subclase UIButton", pero UIButton es en realidad un conjunto de clases (es decir, el tipo real del objeto transparente cambia dependiendo de qué tipo de botón que desea hacer), lo que hace que sea extremadamente difícil subclasificar. A menos que vuelva a escribir UIButton, no hay mucho que pueda hacer en ese enfoque.

Cuando tuve que resolver un problema casi idéntico, se me ocurrió una vista que utiliza la composición para mostrar un proxy UIView, pero aún así permitir la intercepción táctil. Así es como funciona:

@interface MyView : UIView { 
    UIView * visibleView; 
} 

- (id) initWithFrame:(CGRect)frame controlClass:(Class)class; 

@end 


@implementation MyView 

- (id) initWithFrame:(CGRect)frame controlClass:(Class)class { 
    if (self = [super initWithFrame:frame]) { 
    CGRect visibleViewFrame = frame; 
    visibleViewFrame.origin = CGPointZero; 
    visibleView = [[class alloc] initWithFrame:visibleViewFrame]; 
    [visibleView setUserInteractionEnabled:NO]; 
    [self addSubview:visibleView]; 

    [self setUserInteractionEnabled:YES]; 
    [self setBackgroundColor:[UIColor clearColor]]; 
    } 
    return self; 
} 

- (void) dealloc { 
    [visibleView removeFromSuperview]; 
    [visibleView release], visibleView = nil; 
    [super dealloc]; 
} 

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    if (someCondition == YES) { 
    [visibleView touchesBegan:touches withEvent:event]; 
    } 
} 

//and similar methods for touchesMoved:, touchesEnded:, etc 

@end 

La idea básica de esto es que se incrusta en el botón (o lo que sea) en una clase de contenedor (similar a lo que usted describe en su pregunta). Sin embargo, está deshabilitando la interacción en el botón, lo que significa que cuando un usuario toca el botón, el evento tocará "pasará" por el botón y en los botones que contienen la supervista (en este caso, su instancia de MyView). Desde allí, puede procesar el toque de forma adecuada. Si desea que el botón "responda" al toque, simplemente permita que el botón lo haga enviando el mensaje UIResponder apropiado. (Es posible que necesidad de volver a habilitar userInteractionEnabled en la primera visibleView, sin embargo. Estoy seguro de eso.)

Como he dicho anteriormente, he utilizado este enfoque (no esta implementación exacta, pero este patrón) con bastante éxito, cuando necesitaba tener un botón en la interfaz, pero también capturaba el objeto UITouch en sí mismo.

3

puedo sugerir el uso de este enfoque en su lugar:

UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] 
               initWithTarget:self 
               action:@selector(tapDetected:)]; 
    tapRecognizer.numberOfTapsRequired = 1; 
    tapRecognizer.numberOfTouchesRequired = 1; 

    [self.view addGestureRecognizer:tapRecognizer]; 

Usted puede hacer esto desde el supervista, no hay necesidad de hacer que los elementos de interfaz de usuario.

+0

Bueno, UITapGestureRecognizer funcionó muy bien con una UIView que contiene varios UILabel. – joelsand

Cuestiones relacionadas