Pasando a través de toques a UIViews debajo
Tengo un UIView
con 4 botones en él y otro UIView
en la parte superior de la vista de botones. La vista superior contiene un UIImageView
con un UITapGestureRecognizer
en ella.
El comportamiento que estoy tratando de crear es que cuando el usuario toca el UIImageView
alterna entre ser pequeño en la esquina inferior derecha de la pantalla y animar para hacerse más grande. Cuando es grande, quiero que los botones de la vista inferior se desactiven y cuando es pequeño y en la esquina inferior derecha quiero que los toques sean pasado a través de los botones y para que funcionen como de costumbre. Estoy casi allí, pero no puedo conseguir que los toques pasen a través de los botones a menos que desactive el UserInteractions
de la vista superior.
Tengo esto en mi initWithFrame:
de la vista superior:
// Add a gesture recognizer to the image view
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imageTapped:)];
tapGestureRecognizer.cancelsTouchesInView = NO;
[imageView addGestureRecognizer:tapGestureRecognizer];
[tapGestureRecognizer release];
Y este es mi imageTapped:
método:
- (void) imageTapped:(UITapGestureRecognizer *) gestureRecognizer {
// Toggle between expanding and contracting the image
if (expanded) {
[self contractAnimated:YES];
expanded = NO;
gestureRecognizer.cancelsTouchesInView = NO;
self.userInteractionEnabled = NO;
self.exclusiveTouch = NO;
}
else {
[self expandAnimated:YES];
expanded = YES;
gestureRecognizer.cancelsTouchesInView = NO;
self.userInteractionEnabled = YES;
self.exclusiveTouch = YES;
}
}
Con el código anterior, cuando la imagen es grande los botones están inactivos, cuando toco la imagen se encoge y los botones se activan. Sin embargo, la imagen pequeña no recibe el toca y por lo tanto no se expandirá.
Si establezco self.userInteractionEnabled = YES
en ambos casos, entonces la imagen se expande y se contrae cuando se toca, pero los botones nunca reciben toques y actúan como si estuvieran deshabilitados.
¿Hay una distancia para que la imagen se expanda y contraiga cuando se toca, pero para que los botones debajo solo reciban toques si la imagen está en su estado contraído? ¿Estoy haciendo algo estúpido aquí y me estoy perdiendo algo obvio?
Me estoy volviendo absolutamente loco tratando de conseguir esto trabajar para que cualquier ayuda sea apreciada,
Dave
ACTUALIZACIÓN:
Para pruebas adicionales, anulé los métodos touchesBegan:
y touchesCancelled:
y llamé a sus súper implementaciones en mi vista que contiene el UIImageView. Con el código anterior, el touchesCancelled:
nunca se llama y el touchesBegan:
siempre se llama.
Por lo que parece que la vista está recibiendo los toques, simplemente no se pasan a la vista inferior.
UPDATE
Es esto ¿por la forma en que funciona la cadena de respuesta? Mi jerarquía de vista se ve así:
VC - View1
-View2
-imageView1 (has tapGestureRecogniser)
-imageView2
-View3
-button1
-button2
Creo que el sistema operativo primero hace un hitTest como dice View2 está en frente por lo que debe obtener todos los toques y estos nunca se pasan a View3 a menos que userInteractions se establece en NO para View2, en cuyo caso el imageView1 también se impide recibir toques. ¿Es así como funciona y hay una manera de que View2 pase a través de sus toques a View3?
6 answers
El UIGestureRecognizer es una pista falsa, creo. Al final para resolver esto, anulé el método pointInside:withEvent:
de mi UIView:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
BOOL pointInside = NO;
if (CGRectContainsPoint(imageView.frame, point) || expanded) pointInside = YES;
return pointInside;
}
Esto hace que la vista atrape todos los toques si toca la ImageView o si su bandera expandida está activada. Si no está expandido, solo atrape los toques si están en ImageView.
Al devolver NO, la vista de la VC de nivel superior consulta al resto de su jerarquía de vistas en busca de un resultado.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-27 09:59:47
Seleccione su View
en Storyboard
o XIB
y...
O en Swift
view.isUserInteractionEnabled = false
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-30 15:25:13
Busque en el Protocolo UIGestureRecognizerDelegate. Específicamente, gestureRecognizer:shouldReceiveTouch:
Usted querrá hacer cada UIGestureRecognizer
una propiedad de su UIViewController
,
// .h
@property (nonatomic, strong) UITapGestureRecognizer *lowerTap;
// .m
@synthesize lowerTap;
// When you are adding the gesture recognizer to the image view
self.lowerTap = tapGestureRecognizer
Asegúrese de que su UIViewController
un delegado,
[self.lowerTap setDelegate: self];
Entonces, tendrías algo como esto, {[10]]}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if (expanded && gestureRecognizer == self.lowerTap) {
return NO;
}
else {
return YES;
}
}
Por supuesto, este no es el código exacto. Pero este es el patrón general que querrías seguir.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-26 22:26:29
Tengo otra solución. Tengo dos puntos de vista, llamémoslos CustomSubView
que se superponían y ambos deberían recibir los toques. Así que tengo un controlador de vista y una clase UIView personalizada, llamémoslo ViewControllerView
que configuré en interface builder, luego agregué las dos vistas que deberían recibir los toques a esa vista.
Así que intercepté los toques en ViewControllerView
sobrescribiendo hitTest:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
return self;
}
Entonces sobrescribí en ViewControllerView
:
- (void)touchesBegan:(NSSet *)touches
withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
for (UIView *subview in [self.subviews reverseObjectEnumerator])
{
if ([subview isKindOfClass:[CustomSubView class]])
{
[subview touchesBegan:touches withEvent:event];
}
}
}
Haga exactamente lo mismo con touchesMoved
touchesEnded
y touchesCancelled
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-16 09:22:12
@Magic Bullet La solución de Dave pero en Swift
Swift 3
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
var pointInside = false
if commentTextField.frame.contains(point) {
pointInside = true
} else {
commentTextField.resignFirstResponder()
}
return pointInside
}
Lo uso en mi cameraOverlayView para ImagePickerViewController.cameraOverlay para dar al usuario la capacidad de comentar mientras toma una nueva foto
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-06 23:00:49
// this is due to userInteractionEnabled deficiency: the flag stops traversal of subviews
@objc(YourObjcPrefixHereForXibAndStoryboardUseViewTransparentToTouch)
open class ViewTransparentToTouch: UIView
{
public var daisyView: UIView?
override open func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let hitView = super.hitTest(point, with: event)
if hitView === self {
return daisyView
}
return hitView // childView
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-13 14:55:17