UITapGestureRecognizer tik op self.view maar negeer subviews

Ik moet een functie implementeren die code aanroept wanneer ik dubbelklik op de self.view (weergave van UIViewCotroller). Maar het probleem dat ik een ander UI-object in deze weergave heb en ik wil geen herkenningsobject aan ze allemaal koppelen. Ik vond deze methode hieronder om een ​​gebaar naar mijn mening te maken en ik weet hoe het werkt. Op dit moment sta ik voor handicap welke manier ik moet kiezen om deze herkenner te maken en subview te negeren. Om het even welke ideeën? Bedankt.

UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)];
[doubleTap setNumberOfTapsRequired:2];
[self.view addGestureRecognizer:doubleTap];

Antwoord 1, autoriteit 100%

U moet het protocol UIGestureRecognizerDelegatetoepassen in het self-object en de onderstaande methode aanroepen om de weergave te controleren. Binnen deze methode controleert u uw weergave met touch.viewen retourneert u de juiste bool (Ja/Nee). Zoiets als dit:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if ([touch.view isDescendantOfView:yourSubView]) {
        return NO;
    }
    return YES;
}

Bewerken: controleer ook het antwoord van @Ian!

Swift 5

// MARK: UIGestureRecognizerDelegate methods, You need to set the delegate of the recognizer
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
     if touch.view?.isDescendant(of: tableView) == true {
        return false
     }
     return true
}

Antwoord 2, autoriteit 72%

Een andere benadering is om gewoon te vergelijken of de weergave van de aanraking de gebarenweergave is, omdat nakomelingen de voorwaarde niet doorstaan. Een leuke, simpele oneliner:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    return touch.view == gestureRecognizer.view
}

Antwoord 3, autoriteit 14%

En voor de Swift-variant:

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    if touch.view.isDescendantOfView(yourSubView){
        return false
    }
    return true
}

Goed om te weten, isDescendantOfViewretourneert een Boolean-waarde die aangeeft of de ontvanger een subweergave is van een bepaalde weergave of identiek is aan die weergave.


Antwoord 4, autoriteit 11%

Met Swift 5 en iOS 12 heeft UIGestureRecognizerDelegateeen methode genaamd gestureRecognizer(_:shouldReceive:). gestureRecognizer(_:shouldReceive:)heeft de volgende verklaring:

Vraag de afgevaardigde of een gebarenherkenner een object moet ontvangen dat een aanraking voorstelt.

optional func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool

De volledige code hieronder toont een mogelijke implementatie voor gestureRecognizer(_:shouldReceive:). Met deze code zal een tik op een subweergave van de weergave van de ViewController(inclusief imageView) de printHello(_:)niet activeren methode.

import UIKit
class ViewController: UIViewController, UIGestureRecognizerDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(printHello))
        tapGestureRecognizer.delegate = self
        view.addGestureRecognizer(tapGestureRecognizer)
        let imageView = UIImageView(image: UIImage(named: "icon")!)
        imageView.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
        view.addSubview(imageView)
        // ⚠️ Enable user interaction for imageView so that it can participate to touch events.
        // Otherwise, taps on imageView will be forwarded to its superview and managed by it.
        imageView.isUserInteractionEnabled = true
    }
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        // Prevent subviews of a specific view to send touch events to the view's gesture recognizers.
        if let touchedView = touch.view, let gestureView = gestureRecognizer.view, touchedView.isDescendant(of: gestureView), touchedView !== gestureView {
            return false
        }
        return true
    }
    @objc func printHello(_ sender: UITapGestureRecognizer) {
        print("Hello")
    }
}

Een alternatieve implementatie van gestureRecognizer(_:shouldReceive:)kan zijn:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    return gestureRecognizer.view === touch.view
}

Houd er echter rekening mee dat deze alternatieve code niet controleert of touch.vieween subweergave is van gestureRecognizer.view.


Antwoord 5, autoriteit 6%

Volledige snelle oplossing (delegate moet worden geïmplementeerd EN ingesteld voor herkenner(s)):

class MyViewController: UIViewController UIGestureRecognizerDelegate {
    override func viewDidLoad() {
        let doubleTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(onBaseTapOnly))
        doubleTapRecognizer.numberOfTapsRequired = 2
        doubleTapRecognizer.delegate = self
        self.view.addGestureRecognizer(doubleTapRecognizer)
    }
    func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
        if touch.view.isDescendantOfView(self.view){
            return false
        }
        return true
    }
    func onBaseTapOnly(sender: UITapGestureRecognizer) {
        if sender.state == .Ended {
            //react to tap
        }
    }
}

Antwoord 6, autoriteit 4%

Variant die CGPoint gebruikt die u aanraakt (SWIFT 4.0)

class MyViewController: UIViewController, UIGestureRecognizerDelegate {
  func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
// Get the location in CGPoint
    let location = touch.location(in: nil)
// Check if location is inside the view to avoid
    if viewToAvoid.frame.contains(location) {
        return false
    }
    return true
  }
}

Antwoord 7, autoriteit 4%

Duidelijke snelle manier

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    return touch.view == self.view
}

Antwoord 8, autoriteit 2%

Houd er rekening mee dat de gestureRecognizer APIis gewijzigd in:

gestureRecognizer(_:shouldReceive:)

Let in het bijzonder op de onderstrepingstekens (overslaan) voor het externe label van de eerste parameter.

Als ik veel van de hierboven gegeven voorbeelden gebruik, heb ik het evenement niet ontvangen. Hieronder ziet u een voorbeeld dat werkt voor de huidige versies van Swift (3+).

public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    var shouldReceive = false
    if let clickedView = touch.view {
        if clickedView == self.view {
            shouldReceive = true;
        }
    }
    return shouldReceive
}

Antwoord 9

Vergeet naast de bovenstaande oplossingen niet om User Interaction Enabledvan uw subweergave aan te vinken.


Antwoord 10

Ik moest het gebaar in de kinderweergave voorkomen. Het enige dat werkte, was om de eerste weergave toe te staan ​​en te behouden en gebaren in alle volgende weergaven te voorkomen:

  var gestureView: UIView? = nil
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        if (gestureView == nil || gestureView == touch.view){
            gestureView = touch.view
            return true
        }
        return false
     }

Antwoord 11

Swift 4:

touch.viewis nu optioneel, dus gebaseerd op het antwoord van @Antoine:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    if let touchedView = touch.view, touchedView.isDescendant(of: deductibleBackgroundView) {
        return false
    }
    return true
}

Antwoord 12

Als u niet wilt dat uw ‘dubbelklikherkenning’ in conflict komt met uw knoppen en/of andere bedieningselementen, kunt u selfinstellen als UIGestureRecognizerDelegateen implementeren:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool
{
    return !(touch.view is UIControl)
}

Other episodes