2009-02-20 5 views
6

Tengo un UIPickerView que se desvanece a 20% alfa cuando no está en uso. Quiero que el usuario pueda tocar el selector y hacer que vuelva a fundirse.Respondiendo a touchesBegan en UIPickerView en lugar de UIView

Puedo hacer que funcione si pongo un método touchesBegan en la Vista principal, pero esto solo funciona cuando el usuario toca la Vista. Intenté subclasificar UIPickerView y tener un toque BeBe allí, pero no funcionó.

Supongo que tiene algo que ver con la cadena Responder, pero parece que no funciona.

Respuesta

10

He estado buscando una solución a este problema durante más de una semana. Te estoy respondiendo incluso si tu pregunta tiene más de un año esperando que esto ayude a otros.

Lo siento si mi lenguaje no es muy técnico, pero soy bastante nuevo en el desarrollo de Objective-C y iPhone.

Subclase UIpickerView es la forma correcta de hacerlo. Pero debes anular el método - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event. Este es el método que se invoca cada vez que toca la pantalla y devuelve la vista que reaccionará al tacto. En otras palabras, la vista cuyo método touchesBegan:withEvent: se llamará.

¡El UIPickerView tiene 9 subvistas! En la implementación de la clase UIPickerView, - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event no devolverá self (esto significa que no se llamará al touchesBegan:withEvent: que escriba en la subclase) pero devolverá una subvista, exactamente la vista en el índice 4 (una subclase no documentada llamada UIPickerTable).

El truco es hacer que el método - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event para volver self por lo que tienen control sobre los métodos touchesBegan:withEvent:, touchesMoved:withEvent: y touchesEnded:withEvent:.

En estos métodos, para mantener las funcionalidades estándar de UIPickerView, DEBE recordar volver a llamarlas, pero en la subvista UIPickerTable.

Espero que esto tenga sentido. No puedo escribir código ahora, tan pronto como esté en casa, editaré esta respuesta y agregaré algún código.

8

Aquí hay un código que hace lo que quiere:

@interface TouchDetectionView : UIPickerView { 

} 
- (UIView *)getNextResponderView:(NSSet *)touches withEvent:(UIEvent *)event; 
@end 
@implementation TouchDetectionView 

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    UIView * hitTestView = [self getNextResponderView:touches withEvent:event]; 
    [hitTestView touchesBegan:touches withEvent:event]; 
} 

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    UIView * hitTestView = [self getNextResponderView:touches withEvent:event]; 
    [hitTestView touchesMoved:touches withEvent:event]; 
} 

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    UIView * hitTestView = [self getNextResponderView:touches withEvent:event]; 
    [hitTestView touchesEnded:touches withEvent:event]; 
} 

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    UIView * hitTestView = [self getNextResponderView:touches withEvent:event]; 
    [hitTestView touchesCancelled:touches withEvent:event]; 
} 

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    return self; 
} 

- (UIView *)getNextResponderView:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    UITouch * touch = [touches anyObject]; 
    CGPoint point = [touch locationInView:self]; 
    UIView * hitTestView = [super hitTest:point withEvent:event]; 

    return (hitTestView == self) ? nil : hitTestView; 
} 
+0

gracias funcionó :) – ArunGJ

+1

este código parece funcionar, excepto si se produce un toque en el marco que rodea inmediatamente la rueda selector. hacer eso parece causar un bucle infinito de llamadas al método getNextResponderView: withEvent: – pistachionut

+1

ya lo evité devolviendo nil en lugar de hitTestView desde getNextResponderView: withEvent: si toqué la rueda circundante. – ArunGJ

1

Tanto de las respuestas anteriores eran muy útiles, pero tengo una UIPickerView anidada dentro de una UIScrollView. También estoy haciendo un renderizado continuo en otra parte de la pantalla mientras la GUI está presente. El problema es que UIPickerView no se actualiza completamente cuando: se toca una fila no seleccionada, el selector se mueve para que dos filas se ubiquen en el área de selección o se arrastre una fila, pero el dedo se desliza fuera de UIPickerView. Entonces no es hasta que UIScrollView se mueve que el selector se actualiza al instante. Este resultado es feo

La causa del problema: mi renderizado continuo impedía que la animación de UIPickerView obtuviera los ciclos de CPU que necesitaba para finalizar, y por lo tanto para mostrar la selección actual correcta. Mi solución, que funciona, fue esta: en el touchesEnded:withEvent: de UIPickerView, ejecute algo para pausar mi renderizado por un momento. Aquí está el código:

#import "SubUIPickerView.h" 

@implementation SubUIPickerView 

- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    [pickerTable touchesBegan:touches withEvent:event]; 
} 

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

- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    [singleton set_secondsPauseRendering:0.5f]; // <-- my code to pause rendering 

    [pickerTable touchesEnded:touches withEvent:event]; 
} 

- (void) touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    [pickerTable touchesCancelled:touches withEvent:event]; 
} 

- (UIView*) hitTest:(CGPoint)point withEvent:(UIEvent*)event 
{ 
    if (CGRectContainsPoint(self.bounds, point)) 
    { 
     if (pickerTable == nil) 
     { 
      int nSubviews = self.subviews.count; 
      for (int i = 0; i < nSubviews; ++i) 
      { 
       UIView* view = (UIView*) [self.subviews objectAtIndex:i]; 
       if ([view isKindOfClass:NSClassFromString(@"UIPickerTable")]) 
       { 
        pickerTable = (UIPickerTable*) view; 
        break; 
       } 
      } 
     } 
     return self; // i.e., *WE* will respond to the hit and pass it to UIPickerTable, above. 
    } 
    return [super hitTest:point withEvent:event]; 
} 

@end 

y luego la cabecera, SubUIPickerView.h:

@class UIPickerTable; 

@interface SubUIPickerView : UIPickerView 
{ 
    UIPickerTable* pickerTable; 
} 

@end 

Como dije, esto funciona.Renderizar pausas durante 1/2 segundo adicional (ya se detiene al deslizar el UIScrollView) para que la animación UIPickerView finalice. Usar NSClassFromString() significa que no está utilizando ninguna API no documentada. No era necesario jugar con la cadena Responder. ¡Gracias a checcco y Tylerc230 por ayudarme a encontrar mi propia solución!

+0

Esto ya no funciona con UIPickerView de iOS 8. – MatthiasC

+0

@MatthiasC ¿sabes por qué ya no funciona? – stonedauwg

+0

Estas publicaciones sobre UIPickerView son realmente antiguas. Era nuevo y flakey en ese entonces. ¡Apple probablemente (afortunadamente) lo haya reimplementado completamente ahora! – electromaggot

0

Set canCancelContentTouches y delaysContentTouches de vista padre en NO, que trabajaron para mí

Cuestiones relacionadas