playsinline best app iphone objective-c cocoa uiview uibutton

iphone - best - interacción más allá de los límites de uiview



email app android (7)

@jnic, estoy trabajando en iOS SDK 5.0 y para que tu código funcione correctamente tuve que hacer esto:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { if (CGRectContainsPoint(button.frame, point)) { return YES; } return [super pointInside:point withEvent:event]; }

La vista de contenedor en mi caso es un UIButton y todos los elementos secundarios también son UIButtons que pueden moverse fuera de los límites del UIButton padre.

Mejor

¿Es posible que un UIButton (o cualquier otro control para ese asunto) reciba eventos táctiles cuando el marco de UIButton se encuentra fuera del marco de su padre? Porque cuando intento esto, mi UIButton parece no poder recibir ningún evento. ¿Cómo trabajo alrededor de esto?


En la vista principal, puede anular el método de prueba de impacto:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { CGPoint translatedPoint = [_myButton convertPoint:point fromView:self]; if (CGRectContainsPoint(_myButton.bounds, translatedPoint)) { return [_myButton hitTest:translatedPoint withEvent:event]; } return [super hitTest:point withEvent:event]; }

En este caso, si el punto cae dentro de los límites de su botón, reenvía la llamada allí; si no, vuelva a la implementación original.


En mi caso, tenía una subclase UICollectionViewCell que contenía un UIButton . clipsToBounds en la celda y el botón fue visible fuera de los límites de la celda. Sin embargo, el botón no estaba recibiendo eventos táctiles. Pude detectar los eventos táctiles en el botón usando la respuesta de Jack: https://.com/a/30431157/3344977

Aquí hay una versión de Swift:

override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? { let translatedPoint = button.convertPoint(point, fromView: self) if (CGRectContainsPoint(button.bounds, translatedPoint)) { print("Your button was pressed") return button.hitTest(translatedPoint, withEvent: event) } return super.hitTest(point, withEvent: event) }


Para mí (como para otros), la respuesta no fue anular el método hitTest , sino el método pointInside . Tenía que hacer esto solo en dos lugares.

La Supervisión Esta es la opinión de que si tuviera clipsToBounds configuradas en verdadero, haría desaparecer todo este problema. Así que aquí está mi UIView simple en Swift 3:

class PromiscuousView : UIView { override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { return true } }

La subvista Su millaje puede variar, pero en mi caso también tuve que sobrescribir el método pointInside para la subvista que se había decidido que el toque estaba fuera de los límites. El mío está en Objective-C, entonces:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { WEPopoverController *controller = (id) self.delegate; if (self.takeHitsOutside) { return YES; } else { return [super pointInside:point withEvent:event]; } }

Esta respuesta (y algunas otras sobre la misma pregunta) pueden ayudar a aclarar su comprensión.


Rápido:

Donde targetView es la vista que desea recibir el evento (que puede estar total o parcialmente ubicado fuera del marco de su vista principal).

override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? { let pointForTargetView: CGPoint = targetView.convertPoint(point, fromView: self) if CGRectContainsPoint(targetView.bounds, pointForTargetView) { return closeButton } return super.hitTest(point, withEvent: event) }


¿Por qué está pasando esto?

Esto se debe a que cuando su subvista se encuentra fuera de los límites de su supervista, los eventos táctiles que realmente suceden en esa subvista no se enviarán a esa subvista. Sin embargo, SERÁ entregado a su super visión.

Independientemente de si las subvistas se recortan visualmente o no, los eventos táctiles siempre respetan el rectángulo de límites de la supervista de la vista objetivo. En otras palabras, los eventos táctiles que ocurren en una parte de una vista que se encuentra fuera del rectángulo de límites de su supervista no se entregan a esa vista. Link

¿Qué necesitas hacer?

Cuando su supervista reciba el evento táctil mencionado anteriormente, deberá decirle a UIKit explícitamente que mi subvista debe ser la que reciba este evento táctil.

¿Qué hay del código?

En su superview, implemente func hitTest(_ point: CGPoint, with event: UIEvent?)

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { if isHidden || alpha == 0 || clipsToBounds { return nil } // convert the point into subview''s coordinate system let subviewPoint = self.convert(point, to: subview) // if the converted point lies in subview''s bound, tell UIKit that subview should be the one that receives this event if ! subview.isHidden && subview.bounds.contains(subviewPoint) { return subview } return nil }


Sí. Puede anular el hitTest:withEvent: para devolver una vista para un conjunto de puntos más grande que el que contiene la vista. Vea la referencia de clase UIView .

Editar: Ejemplo:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { CGFloat radius = 100.0; CGRect frame = CGRectMake(-radius, -radius, self.frame.size.width + radius, self.frame.size.height + radius); if (CGRectContainsPoint(frame, point)) { return self; } return nil; }

Editar 2: (Después de la aclaración :) Para asegurarse de que el botón se trata como dentro de los límites de los padres, debe anular pointInside:withEvent: en el elemento primario para incluir el marco del botón.

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { if (CGRectContainsPoint(self.view.bounds, point) || CGRectContainsPoint(button.view.frame, point)) { return YES; } return NO; }

Tenga en cuenta que el código que existe para anular el pointInside no es del todo correcto. Como Summon explica a continuación, haz esto:

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { if ( CGRectContainsPoint(self.oversizeButton.frame, point) ) return YES; return [super pointInside:point withEvent:event]; }

Tenga en cuenta que es muy probable que lo haga con self.oversizeButton como IBOutlet en esta subclase de UIView; entonces puedes simplemente arrastrar el "botón de gran tamaño" en cuestión, hacia la vista especial en cuestión. (O, si por alguna razón ha estado haciendo esto mucho en un proyecto, tendría una subclase UIButton especial, y podría mirar a través de su lista de subvista para esas clases.) Espero que ayude.