webentwicklung-frage-antwort-db.com.de

Ermitteln Sie, ob bestimmte UIView unter anderen UIViews berührt wurde

Ich habe 3 UIViews, die auf einer großen Uiview angeordnet sind. Ich möchte wissen, ob der Benutzer den obersten berührt und sich nicht um die anderen kümmert. Ich werde ein paar Buttons in der zweiten UIView und eine UITable in der 3. UIView haben. 

Das Problem ist, dass ich userInteractionEngabled in der ersten Ansicht aktiviere. Das funktioniert zwar, aber alle anderen Ansichten reagieren auf dieselbe Weise, auch wenn ich sie ausschalte. Wenn ich userInteractionEnabled für self.view deaktiviere, antwortet keiner von ihnen. Ich kann auch nicht erkennen, welche Ansicht in der Delegatenmethode touchesBegan berührt wurde.

Mein Code:

UIView *aView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 150)];
aView = userInteractionEnabled = YES;
[self.view addSubview:aView];

UIView *bView = [[UIView alloc] initWithFrame:CGRectMake(0, 150, 320, 50)];
bView.userInteractionEnabled = NO;
[self.view addSubview:bView];

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
//This gets called for a touch anywhere
}
30
Rudiger

Um zu prüfen, ob bestimmte Ansichten in einer anderen Ansicht berührt wurden, können Sie hitTest verwenden. 

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;

Überprüfen Sie in Ihrer benutzerdefinierten Implementierung von touchesBegan jede Berührung in den Kontakten. Der Punkt für die hitTest-Methode kann mit erhalten werden 

- (CGPoint)locationInView:(UIView *)view;

methode, wobei die Ansicht Ihre SuperView ist (die andere Ansichten). 

BEARBEITEN: Hier ist eine schnelle benutzerdefinierte Implementierung:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    CGPoint locationPoint = [[touches anyObject] locationInView:self];
    UIView* viewYouWishToObtain = [self hitTest:locationPoint withEvent:event];
}

Ich hoffe, das war hilfreich. Paul

62
Pawel

In meinem Fall wurde der UIView, den ich finden wollte, vom hotTest nicht zurückgegeben. Der folgende Code hat jedoch besser funktioniert:

    CGPoint locationPoint = [[touches anyObject] locationInView:self.view];
    CGPoint viewPoint = [myImage convertPoint:locationPoint fromView:self.view];
    if ([myImage pointInside:viewPoint withEvent:event]) {
       do something
    }
27
rgadbois

Dies kann auch auf folgende Weise geschehen.

Finden Sie zuerst den Ort der Berührung in der Ansicht, die Sie interessieren:

CGPoint location = [touches.anyObject locationInView:viewYouCareAbout];

Dann sehen Sie, ob der Punkt innerhalb der Grenzen der Ansicht liegt:

BOOL withinBounds = CGRectContainsPoint(viewYouCareAbout.bounds, location);

Wenn es innerhalb der Grenzen liegt, führen Sie Ihre Aktion aus.

Dies kann mit einer Anweisung geschehen, die beispielsweise direkt in einer if-Anweisung verwendet werden kann:

CGRectContainsPoint(viewYouCareAbout.bounds, [touches.anyObject locationInView:viewYouCareAbout])
13
Ben Baron

SWIFT-Code:

 override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        if let touch = touches.first {
            if touch.view == self.view {
                self.hideInView()
            } else {
                return
            }

        }
    }
12
Karthi Keyan

In touchesBegan Überprüfen Sie, ob die berührte Ansicht die gewünschte ist. Sie löste das Problem für mich, als ich versuchte herauszufinden, ob der Benutzer eine bestimmte ImageView berührt hat.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    if ([touch view] ==  imageView ) {
        ... your code to handle the touch
    }
    ...

Wenn Sie den Inhalt für die Ansichtsdimensionen anpassen, müssen Sie die Ansichtsgröße entsprechend ändern. Andernfalls wird das Berührungsereignis auch in Bereichen erkannt, in denen sich der Inhalt in der Ansicht befindet. In meinem Fall, als ich versuchte, das Bildverhältnis mit UIViewContentModeScaleAspectFit beizubehalten, obwohl das Bild in den "weißen Bereichen" den Berührungsereignissen entsprechend angepasst wurde, wurden diese ebenfalls erfasst.

8
Pichirichi

Meine Swift-Version, um zu überprüfen, ob die Berührung in infoView stattgefunden hat:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let touch = touches.first, infoView.bounds.contains(touch.location(in: infoView))  else { return }
    print("touchesBegan") // Replace by your own code
} // touchesBegan
3
KerCodex

Wenn Ihre Anwendung ein Berührungsereignis empfängt, wird ein Treffertestprozess eingeleitet, um zu bestimmen, welche Ansicht das Ereignis empfangen soll. Der Prozess beginnt mit dem Stammverzeichnis der Ansichtshierarchie, normalerweise dem Fenster der Anwendung, und durchsucht die Unteransichten in der Reihenfolge von vorne nach hinten, bis die vorderste Ansicht unter der Berührung gefunden wird. Diese Ansicht wird zur Trefferanzeige und empfängt das Berührungsereignis. Jede an diesem Prozess beteiligte Ansicht testet zunächst, ob der Ereignisort innerhalb seiner Grenzen liegt. Erst nachdem der Test erfolgreich war, leitet die Ansicht das Ereignis an die Unteransichten weiter, um weitere Treffer zu testen. Wenn sich Ihre Ansicht unter der Berührung befindet, sich jedoch außerhalb der Grenzen der übergeordneten Ansicht befindet, kann die übergeordnete Ansicht den Ort des Ereignisses nicht testen und das Berührungsereignis nicht an Ihre Ansicht übergeben.

Eine Lösung für dieses Problem besteht darin, das Layout der Ansichtshierarchie so zu ändern, dass sich Ihre Ansicht innerhalb der Grenzen der übergeordneten Ansicht befindet. Wenn aus bestimmten Gründen das vorhandene Layout beibehalten werden muss, können Sie das Treffertest-Verhalten der übergeordneten Ansicht ändern, sodass die Berührungsereignisse nicht ignoriert werden. Dies kann durch Überschreiben der - (UIView *) hitTest: withEvent: -Methode der Klasse der übergeordneten Ansicht erreicht werden

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

    // Convert the point to the target view's coordinate system.
    // The target view isn't necessarily the immediate subview
    CGPoint pointForTargetView = [self.targetView convertPoint:point fromView:self];

    if (CGRectContainsPoint(self.targetView.bounds, pointForTargetView)) {

        // The target view may have its view hierarchy,
        // so call its hitTest method to return the right hit-test view
        return [self.targetView hitTest:pointForTargetView withEvent:event];
    }

    return [super hitTest:point withEvent:event]; }

Andere mögliche Ursachen für dieses Problem sind:

Die userInteractionEnabled-Eigenschaft Ihrer Ansicht oder einer ihrer übergeordneten Ansichten wird auf NO festgelegt. Die Anwendung hat die Methode beginIgnoringInteractionEvents aufgerufen, ohne dass ein entsprechender Aufruf der Methode endIgnoringInteractionEvents erfolgt ist. Sie sollten sicherstellen, dass die userInteractionEnabled-Eigenschaft auf YES festgelegt ist und die Anwendung die Benutzerereignisse nicht ignoriert, wenn die Ansicht interaktiv sein soll.

Wenn Ihre Ansicht während der Animation keine Berührungsereignisse empfängt, ist dies darauf zurückzuführen, dass die Animationsmethoden von UIView Berührungsereignisse normalerweise deaktivieren, während Animationen ausgeführt werden. Sie können dieses Verhalten ändern, indem Sie die Option UIViewAnimationOptionAllowUserInteraction beim Starten der UIView-Animation entsprechend konfigurieren.

Eine andere Lösung ist

Fügen Sie der Ansicht Ihre eigene benutzerdefinierte Implementierung hinzu

class CustomView: YourParentView {

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

        super.hitTest(point, with: event)
        return overlapHitTest(point: point, withEvent: event)
    }
}


extension UIView {

    func overlapHitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {

        // 1
        if !self.isUserInteractionEnabled || self.isHidden || self.alpha == 0 {

            return nil
        }

        // 2
        var hitView: UIView? = self
        if !self.point(inside: point, with: event) {

            if self.clipsToBounds {

                return nil
            } else {

                hitView = nil
            }
        }

        // 3
        for subview in self.subviews.reversed() {

            let insideSubview = self.convert(point, to: subview)
            if let sview = subview.overlapHitTest(point: insideSubview, withEvent: event) {
                return sview
            }
        }
        return hitView
    }
}
0

Das hat für mich funktioniert:

func respondToGesture(gesture: UIGestureRecognizer) {
    let containsPoint = CGRectContainsPoint(targetView.bounds, gesture.locationInView(targetView))
}
0
Andy