Uigesturerecognizer blokuje subview do obsługi zdarzeń dotykowych

Próbuję dowiedzieć się, jak to się robi we właściwy sposób. Próbowałem zobrazować sytuację.: Tutaj wpisz opis obrazka

Dodaję UITableView jako podgląd UIView. UIView odpowiada na tap-and pinchGestureRecognizer, ale kiedy to robi, widok tableview przestaje reagować na te dwa gesty(nadal reaguje na przesunięcia).

Zrobiłem to z poniższym kodem, ale oczywiście nie jest to miłe rozwiązanie i jestem pewien, że jest lepszy sposób. To jest umieszczone w UIView (The superview):

-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    if([super hitTest:point withEvent:event] == self) {
        for (id gesture in self.gestureRecognizers) {
            [gesture setEnabled:YES];
        }
        return self;
    }
    for (id gesture in self.gestureRecognizers) {
        [gesture setEnabled:NO];
    }
    return [self.subviews lastObject];
}
Author: Mr.Kushwaha, 2011-03-07

10 answers

Miałem bardzo podobny problem i znalazłem swoje rozwiązanie w tym więc pytaniu . Podsumowując, Ustaw siebie jako delegata dla swojego UIGestureRecognizer, a następnie sprawdź docelowy widok, zanim pozwolisz rozpoznawaczowi przetworzyć dotyk. Odpowiednia metoda delegata to:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
       shouldReceiveTouch:(UITouch *)touch
 179
Author: Justin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:17:54

Blokowanie zdarzeń dotyku do podglądów podrzędnych jest domyślnym zachowaniem. Możesz zmienić to zachowanie:

UITapGestureRecognizer *r = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(agentPickerTapped:)];
r.cancelsTouchesInView = NO;
[agentPicker addGestureRecognizer:r];
 100
Author: Clive Paterson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-18 06:45:41

Wyświetlałem rozwijany subview, który miał swój własny widok tableview. W rezultacie touch.view czasami zwracają klasy takie jak UITableViewCell. Musiałem przejść przez superklasę (es), aby upewnić się, że jest to podklasa, którą myślałem, że jest: {]}

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    UIView *view = touch.view;
    while (view.class != UIView.class) {
        // Check if superclass is of type dropdown
        if (view.class == dropDown.class) { // dropDown is an ivar; replace with your own
            NSLog(@"Is of type dropdown; returning NO");
            return NO;
        } else {
            view = view.superview;
        }
    }

    return YES;
}
 5
Author: joslinm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-24 11:43:30

Jedną z możliwości jest podklasowanie rozpoznawania gestów (jeśli jeszcze tego nie zrobiłeś) i nadpisanie -touchesBegan:withEvent: tak, aby określić, czy każdy dotyk rozpoczął się w wyłączonym subview i wywołanie -ignoreTouch:forEvent: dla tego dotyku, jeśli tak się stało.

Oczywiście, musisz również dodać właściwość, aby śledzić wykluczony subview, lub może lepiej, tablicę wykluczonych podviewów.

 4
Author: Caleb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-24 10:41:44

Możliwe jest obejście się bez dziedziczenia żadnej klasy.

Możesz sprawdzić gestureRecognizers w selektorze wywołania zwrotnego gesture

If view.gestureRecognizers nie zawiera twojego gesturerecognizera, po prostu zignoruj go

Na przykład

- (void)viewDidLoad
{
    UITapGestureRecognizer *singleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self     action:@selector(handleSingleTap:)];
    singleTapGesture.numberOfTapsRequired = 1;
}

Sprawdź widok.gestureRecognizers here

- (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer
{
    UIEvent *event = [[UIEvent alloc] init];
    CGPoint location = [gestureRecognizer locationInView:self.view];

    //check actually view you hit via hitTest
    UIView *view = [self.view hitTest:location withEvent:event];

    if ([view.gestureRecognizers containsObject:gestureRecognizer]) {
        //your UIView
        //do something
    }
    else {
        //your UITableView or some thing else...
        //ignore
    }
}
 2
Author: Pin Shih Wang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-14 05:39:23

Budowanie na @ Pin Shih Wang odpowiedz . Ignorujemy wszystkie stuknięcia inne niż te w widoku zawierającym rozpoznawanie gestów stukania. Wszystkie stuknięcia są przekazywane do hierarchii widoku tak normalnie, jak ustawiliśmy tapGestureRecognizer.cancelsTouchesInView = false. Oto kod w Swift3 / 4:

func ensureBackgroundTapDismissesKeyboard() {
    let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
    tapGestureRecognizer.cancelsTouchesInView = false
    self.view.addGestureRecognizer(tapGestureRecognizer)
}

@objc func handleTap(recognizer: UIGestureRecognizer) {
    let location = recognizer.location(in: self.view)
    let hitTestView = self.view.hitTest(location, with: UIEvent())
    if hitTestView?.gestureRecognizers?.contains(recognizer) == .some(true) {
        // I dismiss the keyboard on a tap on the scroll view
        // REPLACE with own logic
        self.view.endEditing(true)
    }
}
 2
Author: Nick Ager,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-27 12:33:54

Stworzyłem podklasę UIGestureRecognizer przeznaczoną do blokowania wszystkich rozpoznawaczy gestów dołączonych do podglądu określonego widoku.

To część mojego projektu WEPopover. Możesz go znaleźć tutaj .
 1
Author: Werner Altewischer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-23 10:10:21

Ja też robiłem popover i tak to zrobiłem

func didTap(sender: UITapGestureRecognizer) {

    let tapLocation = sender.locationInView(tableView)

    if let _ = tableView.indexPathForRowAtPoint(tapLocation) {
        sender.cancelsTouchesInView = false
    }
    else {
        delegate?.menuDimissed()
    }
}
 0
Author: Maria,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-29 20:06:01

Możesz go wyłączyć i włączyć.... w moim kodzie zrobiłem coś takiego, ponieważ musiałem go wyłączyć, gdy klawiatura nie pokazywała się, możesz zastosować to do swojej sytuacji: {]}

Call this is viewdidload etc:

NSNotificationCenter    *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(notifyShowKeyboard:) name:UIKeyboardDidShowNotification object:nil];
[center addObserver:self selector:@selector(notifyHideKeyboard:) name:UIKeyboardWillHideNotification object:nil];

Następnie utwórz dwie metody:

-(void) notifyShowKeyboard:(NSNotification *)inNotification 
{
    tap.enabled=true;  // turn the gesture on
}

-(void) notifyHideKeyboard:(NSNotification *)inNotification 
{
    tap.enabled=false;  //turn the gesture off so it wont consume the touch event
}

To wyłącza kran. Musiałem zmienić tap w zmienną instancji i zwolnić go w dealloc choć.

 0
Author: j2emanue,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-18 06:25:35

Zaimplementuj delegata dla wszystkich rozpoznawaczy parentView i umieść metodę gestureRecognizer w delegacie odpowiedzialnym za jednoczesne wyzwalanie rozpoznawaczy:

func gestureRecognizer(UIGestureRecognizer,       shouldBeRequiredToFailByGestureRecognizer:UIGestureRecognizer) -> Bool {
if (otherGestureRecognizer.view.isDescendantOfView(gestureRecognizer.view)) {
    return true
    } else {
    return false
}

}

U można użyć metod fail, jeśli chcemy, aby dzieci były wyzwalane, ale nie rozpoznawane przez rodziców:

Https://developer.apple.com/reference/uikit/uigesturerecognizerdelegate

 0
Author: user7270881,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-12 11:01:32