iOS: reenviar todos los toques a través de una vista


75

Tengo una vista superpuesta encima de muchas otras vistas. Solo estoy usando el exceso para detectar algunos toques en la pantalla, pero aparte de eso, no quiero que la vista pare el comportamiento de otras vistas debajo, que son scrollviews, etc. ¿Cómo puedo reenviar todos los toques a través de esta vista de superposición? Es un subcals de UIView.

0

intentar algo como esto ...

for (UIView *view in subviews) 
    [view touchesBegan:touches withEvent:event]; 

El código anterior, en su método touchesBegan por ejemplo, pasarían los toques a todos los subvistas de vista.

+6

El problema con este enfoque que yo sepa es que el intento de reenviar toques a las clases de marco UIKit será más a menudo no tienen efecto. Según la documentación de Apple, las clases de framework UIKit no están diseñadas para recibir toques que tengan la propiedad view establecida en alguna otra vista. Entonces, este enfoque funciona principalmente para subclases personalizadas de UIView. 02 mar. 112011-03-02 23:05:35


4

Si la vista que desea reenviar los toques que no le pase a ser una subvista/supervista, se puede establecer una propiedad personalizada en la subclase UIView así:

@interface SomeViewSubclass : UIView { 

    id forwardableTouchee; 

} 
@property (retain) id forwardableTouchee; 

Asegúrese de sintetizar en su .m:

@synthesize forwardableTouchee; 

y después incluir lo siguiente en cualquiera de sus métodos UIResponder como:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 

    [self.forwardableTouchee touchesBegan:touches withEvent:event]; 

} 

Dondequiera que instancia su UIView, establezca la propiedad forwardableTouchee a cualquier punto de vista desea los eventos que se remitirá a:

SomeViewSubclass *view = [[[SomeViewSubclass alloc] initWithFrame:someRect] autorelease]; 
    view.forwardableTouchee = someOtherView; 

75

Para pasar toques de una vista de superposición de los puntos de vista por debajo, poner en práctica el método siguiente la UIView:

Objective-C:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { 
    NSLog(@"Passing all touches to the next view (if any), in the view stack."); 
    return NO; 
} 

Swift:

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { 
    print("Passing all touches to the next view (if any), in the view stack.") 
    return false 
} 
+2

Tengo el mismo problema, pero lo que quiero es si estoy haciendo zoom/girando/moviendo la vista con gesto, entonces debería devolver sí y para el evento de descanso debería devolver no, ¿cómo puedo lograr esto? 12 ago. 132013-08-12 06:27:33


58
myWebView.userInteractionEnabled = NO; 

era todo lo que necesitaba!


38

Este es un hilo viejo, pero apareció en una búsqueda, así que pensé en agregar mi 2c. Tengo un UIView cubierta con subvistas, y sólo quiero interceptar los toques que golpean una de las subvistas, por lo que he modificado la respuesta de PixelCloudSt a

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    for (UIView* subview in self.subviews) { 
     if ([subview hitTest:[self convertPoint:point toView:subview] withEvent:event] != nil) { 
      return YES; 
     } 
    } 
    return NO; 
} 
+1

Debe crear una subclase UIView personalizada (o una subclase de cualquier otra subclase UIView como UIImageView o lo que sea) y anular esta función. En esencia, la subclase puede tener una "interfaz" totalmente vacía en el archivo .h, y la función anterior es el contenido completo de la "implementación". 07 mar. 142014-03-07 16:01:14


-1

Como sugiere @PixelCloudStv si usted quiere lanzar tocado de una vista a otro, pero con un poco de control adicional sobre este proceso - subclase UIView

// cabecera

@interface TouchView : UIView 

@property (assign, nonatomic) CGRect activeRect; 

@end 

// aplicación

#import "TouchView.h" 

@implementation TouchView 

#pragma mark - Ovverride 

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    BOOL moveTouch = YES; 
    if (CGRectContainsPoint(self.activeRect, point)) { 
     moveTouch = NO; 
    } 
    return moveTouch; 
} 

@end 

Después en interfaceBuilder simplemente configure la clase de vista en TouchView y establezca el rect activo con su rect. También puede cambiar e implementar otra lógica.


3

Tuve un problema similar con un UIStackView (pero podría ser cualquier otra vista). Mi configuración es la siguiente: View controller with containerView and StackView

Es un caso clásico en el que tengo un contenedor que necesita para ser colocado en el fondo, con botones en el lado. Para propósitos de diseño, incluí los botones en un UIStackView, pero ahora la parte central (vacía) del stackView intercepta toques :-(

Lo que hice fue crear una subclase de UIStackView con una propiedad que definiera el subView que debería ser touchable. Ahora, cualquier toque en los botones laterales (incluidos en la matriz * viewsWithActiveTouch *) se dará a los botones, mientras que cualquier toque en la vista de la pila en cualquier lugar que estas vistas no será interceptado, y por lo tanto se pasará a lo que sea por debajo de la vista apilada.

/** Subclass of UIStackView that does not accept touches, except for specific subviews given in the viewsWithActiveTouch array */ 
class NoTouchStackView: UIStackView { 

    var viewsWithActiveTouch: [UIView]? 

    override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? { 

    if let activeViews = viewsWithActiveTouch { 
     for view in activeViews { 
      if CGRectContainsPoint(view.frame, point) { 
       return view 

      } 
     } 
    } 
    return nil 
    } 
} 

14

versión mejorada de respuesta @fresidue. puede utilizar esta subclase UIView vista tan transparente que pasa toques ou al costado de su subvista. Implementación en Objective-C:

@interface PassthroughView : UIView 

@end 

@implementation PassthroughView 

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    for (UIView *view in self.subviews) { 
     if (!view.hidden && [view pointInside:[self convertPoint:point toView:view] withEvent:event]) { 
      return YES; 
     } 
    } 
    return NO; 
} 

@end 

y en Swift:

class PassthroughView: UIView { 
    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { 
    return subviews.contains(where: { 
     !$0.isHidden && $0.point(inside: self.convert(point, to: $0), with: event) 
    }) 
    } 
}