puedo - no aparece invitados en calendario iphone
Manejo de eventos para iOS: cómo hitTest: withEvent: y pointInside: withEvent: ¿están relacionados? (6)
Creo que estás confundiendo las subclases con la jerarquía de vistas. Lo que dice el documento es el siguiente. Supongamos que tiene esta jerarquía de vistas. Por jerarquía, no estoy hablando de jerarquía de clases, sino de vistas dentro de la jerarquía de vistas, de la siguiente manera:
+----------------------------+
|A |
|+--------+ +------------+ |
||B | |C | |
|| | |+----------+| |
|+--------+ ||D || |
| |+----------+| |
| +------------+ |
+----------------------------+
Digamos que metiste el dedo dentro D
Esto es lo que sucederá:
-
hitTest:withEvent:
sehitTest:withEvent:
enA
, la vista superior de la jerarquía de vistas. -
pointInside:withEvent:
se llama recursivamente en cada vista.-
pointInside:withEvent:
sepointInside:withEvent:
aA
y devuelveYES
-
pointInside:withEvent:
sepointInside:withEvent:
enB
y devuelveNO
-
pointInside:withEvent:
sepointInside:withEvent:
aC
y devuelveYES
-
pointInside:withEvent:
sepointInside:withEvent:
enD
y devuelveYES
-
- En las vistas que devolvieron
YES
, mirarán hacia abajo en la jerarquía para ver la subvista donde se realizó el toque. En este caso, deA
,C
yD
, seráD
-
D
será la vista de prueba
Si bien la mayoría de los documentos de Apple están muy bien escritos, creo que la '' Guía de manejo de eventos para iOS '' es una excepción. Es difícil para mí entender claramente lo que se ha descrito allí.
El documento dice,
En la prueba de aciertos, una ventana llama a
hitTest:withEvent:
en la vista superior de la jerarquía de vistas; este método procede llamando recursivamente apointInside:withEvent:
en cada vista en la jerarquía de vista que devuelve SÍ, avanzando hacia abajo en la jerarquía hasta que encuentra la subvista dentro de cuyos límites se realizó el toque. Esa vista se convierte en la vista de prueba de golpe.
Entonces, ¿solo es así hitTest:withEvent:
de la vista más alta es pointInside:withEvent:
por el sistema, que llama a pointInside:withEvent:
de todas las subvistas, y si el retorno de una subvista específica es YES, entonces llama a pointInside:withEvent:
de las subclases de esa subvista?
El fragmento de @lion funciona como un hechizo. Lo porté para acelerar 2.1 y lo usé como una extensión para UIView. Lo estoy publicando aquí en caso de que alguien lo necesite.
extension UIView {
func overlapHitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
// 1
if !self.userInteractionEnabled || self.hidden || self.alpha == 0 {
return nil
}
//2
var hitView: UIView? = self
if !self.pointInside(point, withEvent: event) {
if self.clipsToBounds {
return nil
} else {
hitView = nil
}
}
//3
for subview in self.subviews.reverse() {
let insideSubview = self.convertPoint(point, toView: subview)
if let sview = subview.overlapHitTest(insideSubview, withEvent: event) {
return sview
}
}
return hitView
}
}
Para usarlo, solo anule hitTest: point: withEvent en su uiview de la siguiente manera:
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
let uiview = super.hitTest(point, withEvent: event)
print("hittest",uiview)
return overlapHitTest(point, withEvent: event)
}
Encuentro este Hit-Testing en iOS para ser muy útil
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if (!self.isUserInteractionEnabled || self.isHidden || self.alpha <= 0.01) {
return nil;
}
if ([self pointInside:point withEvent:event]) {
for (UIView *subview in [self.subviews reverseObjectEnumerator]) {
CGPoint convertedPoint = [subview convertPoint:point fromView:self];
UIView *hitTestView = [subview hitTest:convertedPoint withEvent:event];
if (hitTestView) {
return hitTestView;
}
}
return self;
}
return nil;
}
Editar Swift 4:
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if self.point(inside: point, with: event) {
return super.hitTest(point, with: event)
}
guard isUserInteractionEnabled, !isHidden, alpha > 0 else {
return nil
}
for subview in subviews.reversed() {
let convertedPoint = subview.convert(point, from: self)
if let hitView = subview.hitTest(convertedPoint, with: event) {
return hitView
}
}
return nil
}
Gracias por las respuestas, me ayudaron a resolver la situación con vistas "superpuestas".
+----------------------------+
|A +--------+ |
| |B +------------------+ |
| | |C X | |
| | +------------------+ |
| | | |
| +--------+ |
| |
+----------------------------+
Asuma X
- toque del usuario. pointInside:withEvent:
on B
devuelve NO
, así que hitTest:withEvent:
devuelve A
Escribí una categoría en UIView
para manejar el problema cuando necesitas recibir el toque en la vista más visible .
- (UIView *)overlapHitTest:(CGPoint)point withEvent:(UIEvent *)event {
// 1
if (!self.userInteractionEnabled || [self isHidden] || self.alpha == 0)
return nil;
// 2
UIView *hitView = self;
if (![self pointInside:point withEvent:event]) {
if (self.clipsToBounds) return nil;
else hitView = nil;
}
// 3
for (UIView *subview in [self.subviewsreverseObjectEnumerator]) {
CGPoint insideSubview = [self convertPoint:point toView:subview];
UIView *sview = [subview overlapHitTest:insideSubview withEvent:event];
if (sview) return sview;
}
// 4
return hitView;
}
- No debemos enviar eventos táctiles para vistas ocultas o transparentes, o vistas con
userInteractionEnabled
establecido enNO
; - Si el tacto está dentro de
self
, elself
se considerará como resultado potencial. - Compruebe recursivamente todas las subvistas para golpear. Si hay alguno, devuélvalo.
- De lo contrario, devuelve self o nil dependiendo del resultado del paso 2.
Tenga en cuenta que [self.subviewsreverseObjectEnumerator]
necesario para seguir la jerarquía de vista desde arriba hacia abajo. Y compruebe si hay clipsToBounds
en los clipsToBounds
para asegurarse de no probar las subvistas enmascaradas.
Uso:
- Importar categoría en su vista subclase.
- Reemplazar
hitTest:withEvent:
con esto
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
return [self overlapHitTest:point withEvent:event];
}
La Guía oficial de Apple también proporciona algunas buenas ilustraciones.
Espero que esto ayude a alguien.
Parece una pregunta bastante básica. Pero estoy de acuerdo con usted, el documento no es tan claro como otros documentos, así que esta es mi respuesta.
La implementación de hitTest:withEvent:
en UIResponder hace lo siguiente:
- Llama
pointInside:withEvent:
ofself
- Si el resultado es NO,
hitTest:withEvent:
devuelvenil
. El fin de la historia. - Si el resultado es SÍ, envía
hitTest:withEvent:
messages a sus subvistas. comienza desde la subvista de nivel superior y continúa hasta otras vistas hasta que una subvista devuelve un objeto nonil
o todas las subvistas reciben el mensaje. - Si una subvista devuelve un objeto no
nil
la primera vez, el primerhitTest:withEvent:
devuelve ese objeto. El fin de la historia. - Si ninguna subvista devuelve un objeto no
nil
, la primerahitTest:withEvent:
devuelveself
Este proceso se repite recursivamente, por lo que normalmente la vista de hoja de la jerarquía de vista se devuelve finalmente.
Sin embargo, puede anular hitTest:withEvent
para hacer algo diferente. En muchos casos, anulando pointInside:withEvent:
es más simple y aún proporciona suficientes opciones para modificar el manejo de eventos en su aplicación.
Se muestra como este fragmento!
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if (self.hidden || !self.userInteractionEnabled || self.alpha < 0.01)
{
return nil;
}
if (![self pointInside:point withEvent:event])
{
return nil;
}
__block UIView *hitView = self;
[self.subViews enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
CGPoint thePoint = [self convertPoint:point toView:obj];
UIView *theSubHitView = [obj hitTest:thePoint withEvent:event];
if (theSubHitView != nil)
{
hitView = theSubHitView;
*stop = YES;
}
}];
return hitView;
}