Ich habe ein UIView
mit 4 Schaltflächen und ein weiteres UIView
über der Schaltflächenansicht. Die oberste Ansicht enthält ein UIImageView
mit einem UITapGestureRecognizer
.
Das Verhalten, das ich zu erstellen versuche, besteht darin, dass der Benutzer, wenn er auf UIImageView
tippt, zwischen klein in der unteren rechten Ecke des Bildschirms und animiert, um größer zu werden, umschaltet. Wenn es groß ist, sollen die Schaltflächen in der unteren Ansicht deaktiviert werden, und wenn es klein ist und sich in der unteren rechten Ecke befinden, sollen die Berührungen an die Schaltflächen weitergegeben werden, damit sie wie gewohnt funktionieren. Ich bin fast da, aber ich kann nicht die Berührungen bekommen, um zu den Knöpfen durchzugehen, es sei denn, ich deaktiviere das UserInteractions
der Draufsicht.
Ich habe das in meinem initWithFrame:
der Draufsicht:
// 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];
und ich das ist mein imageTapped:
Methode:
- (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;
}
}
Mit dem obigen Code sind die Schaltflächen inaktiv, wenn ich das Bild berühre, verkleinert es sich und die Schaltflächen werden aktiv. Das kleine Bild erhält jedoch keine Berührungen und wird daher nicht erweitert.
Wenn ich self.userInteractionEnabled = YES
In beiden Fällen wird das Bild beim Berühren vergrößert und verkleinert, aber die Schaltflächen werden nie berührt und wirken so, als ob sie deaktiviert wären.
Ist es nicht möglich, das Bild beim Berühren zu vergrößern und zu verkleinern, aber die Schaltflächen darunter erhalten nur Berührungen, wenn sich das Bild im Status "Kontrahiert" befindet? Mache ich hier etwas Dummes und vermisse etwas Offensichtliches?
Ich werde absolut verrückt, wenn ich versuche, das zum Laufen zu bringen, also wäre jede Hilfe dankbar.
Dave
PDATE:
Zum weiteren Testen habe ich die touchesBegan:
und touchesCancelled:
Methoden und nannte ihre Super-Implementierungen in meiner Ansicht mit dem UIImageView. Mit dem obigen Code wird das touchesCancelled:
wird nie aufgerufen und der touchesBegan:
wird immer aufgerufen.
Es scheint also, dass die Ansicht die Berührungen bekommt, sie werden einfach nicht an die Ansicht darunter weitergegeben.
UPDATE
Liegt das an der Funktionsweise der Antwortkette? Meine Ansichtshierarchie sieht folgendermaßen aus:
VC - View1
-View2
-imageView1 (has tapGestureRecogniser)
-imageView2
-View3
-button1
-button2
Ich denke, dass das Betriebssystem zuerst einen HitTest durchführt, da View2 vorne ist, sodass alle Berührungen abgerufen werden sollten. Diese werden niemals an View3 weitergeleitet, es sei denn, userInteractions ist für View2 auf NO gesetzt. In diesem Fall wird auch verhindert, dass imageView1 Berührungen empfängt. Funktioniert das so und gibt es eine Möglichkeit für View2, durch seine Berührungen zu View3 zu gelangen?
Der UIGestureRecognizer ist meiner Meinung nach ein roter Hering. Zum Schluss habe ich das pointInside:withEvent:
Methode meines UIView:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
BOOL pointInside = NO;
if (CGRectContainsPoint(imageView.frame, point) || expanded) pointInside = YES;
return pointInside;
}
Dies bewirkt, dass die Ansicht alle Berührungen abfängt, wenn Sie entweder die Bildansicht berühren oder das erweiterte Flag gesetzt ist. Wenn es nicht erweitert ist, fangen Sie die Berührungen nur ein, wenn sie sich in der Bildansicht befinden.
Wenn Sie NEIN zurückgeben, fragt die Ansicht der obersten Ebene die restliche Ansichtshierarchie ab und sucht nach einem Treffer.
Wählen Sie Ihr View
in Storyboard
oder XIB
und ...
oder in Swift
view.isUserInteractionEnabled = false
Schauen Sie in das IGestureRecognizerDelegate Protocol . Insbesondere gestureRecognizer:shouldReceiveTouch:
Sie möchten jedes UIGestureRecognizer
zu einer Eigenschaft Ihres UIViewController
machen,
// .h
@property (nonatomic, strong) UITapGestureRecognizer *lowerTap;
// .m
@synthesize lowerTap;
// When you are adding the gesture recognizer to the image view
self.lowerTap = tapGestureRecognizer
Stellen Sie sicher, dass Sie aus Ihrem UIViewController
einen Stellvertreter machen,
[self.lowerTap setDelegate: self];
Dann hättest du so etwas,
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if (expanded && gestureRecognizer == self.lowerTap) {
return NO;
}
else {
return YES;
}
}
Dies ist natürlich kein genauer Code. Dies ist jedoch das allgemeine Muster, dem Sie folgen möchten.
@Magic Bullet Daves Lösung aber in Swift
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
}
Ich verwende es in meinem CameraOverlayView für ImagePickerViewController.cameraOverlay, um dem Benutzer die Möglichkeit zu geben, beim Aufnehmen eines neuen Fotos Kommentare abzugeben
Ich habe eine andere Lösung. Ich habe zwei Ansichten, nennen wir sie CustomSubView
, die sich überlappten, und sie sollten beide die Berührungen erhalten. Ich habe also einen Ansichtscontroller und eine benutzerdefinierte UIView-Klasse. Nennen wir sie ViewControllerView
, die ich im Interface Builder festgelegt habe. Dann habe ich die beiden Ansichten hinzugefügt, die die Berührungen für diese Ansicht erhalten sollen.
Also habe ich die Berührungen in ViewControllerView
abgefangen, indem ich hitTest überschrieben habe:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
return self;
}
Dann überschrieb ich in 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];
}
}
}
Machen Sie dasselbe mit touchesMoved
touchesEnded
und touchesCancelled
.
// 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
}
}