webentwicklung-frage-antwort-db.com.de

Übergeben von Berührungen an UIViews darunter

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?

64

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.

91

Wählen Sie Ihr View in Storyboard oder XIB und ...


enter image description here


oder in Swift

view.isUserInteractionEnabled = false
59
Michael

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.

6
john

@Magic Bullet Daves Lösung aber in Swift

Schnell 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
}

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

3
imike

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 touchesMovedtouchesEnded und touchesCancelled.

3
Nico S.
// 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
}
}
0
Anton Tropashko