UITapGestureRecognizer - однократний та подвійний дотик


156

Я намагаюся додати 2 UITapGestureRecognizersдля перегляду, один для одного натискання та один для подій подвійного натискання. Розпізнавач одного дотику працює як очікується (самостійно). Але я, здається, не в змозі змусити функцію подвійного розпізнавання працювати.

Намагалися експериментувати з властивостями , як: cancelsTouchesInView, delaysTouchesBeganі , delaysTouchesEndedале до сих пір не працює.

Коли я подвійно натискаю, розпізнавальник одного дотику завжди буде активований, а подія подвійного натискання також буде відправлена ​​в суперпогляд. Але, як видається, користувацький розпізнавальник подвійного дотику взагалі не повідомляється.

Здається, що документація свідчить про те, що 3 властивості, згадані вище, можна використовувати для цієї мети. Але я просто не впевнений, які значення слід встановити та на якому розпізнавачі (одинарних, подвійних або обох). Сподіваюся, хтось знайомий з цим може допомогти.

Далі йде останній оновлений блок коду.

// ****** gesture recognizers ******

- (void)addSingleAndDoubleTapGestureRecognizersToView:(UIView *)view
{
    // single tap    
    UITapGestureRecognizer *singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget: tableViewController action: @selector(handleSingleTapOnView:)];                                 
    [singleTapRecognizer setNumberOfTouchesRequired:1];
    [view addGestureRecognizer: singleTapRecognizer];

    // double tap 
    UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget: tableViewController action: @selector (handleDoubleTapOnView:)];        
    [doubleTapRecognizer setNumberOfTouchesRequired:2];         
    [singleTapRecognizer requireGestureRecognizerToFail: doubleTapRecognizer];
    [view addGestureRecognizer: doubleTapRecognizer];         
}

- (void)handleSingleTapOnView:(id)sender
{

}

- (void)handleDoubleTapOnView:(id)sender
{

}

30
Випадковий коментар: підкреслення в іменах змінних змусить більшість програмістів Objective-C не змінюватись. Найгірше те, що назви змінних не є описовими. Чому б просто не використовувати singleTapRecognizer та doubleTapRecognizer (чи щось подібне)? Набирати потрібно секунду більше, але робить ваш код нескінченно більш читабельним.
— UIAdam

Дякую за пораду, погоджуйтесь з вами, що назви змінних повинні бути більш описовими. Але цей конкретний сегмент коду ще не був доопрацьований і він опублікує більш відшліфований та описовий код, як було запропоновано ...
— Стенлі

У випадку, якщо хтось інший має подібну проблему. Я намагався отримати подвійний тапізнавальний механізм, який працює спільно, швидко (один кран працював нормально, але подвійний дотик не був). Я перетягнув розпізнавачів на сцену за допомогою раскадровки. У мене були обробники і вислів: singleTapRecognizer.requireGestureRecognizerToFail (doubleTabRecognizer) всередині моєї viewDidLoad, але все ще немає подвійного торкання. Мій відсутній фрагмент головоломки полягав у перетягуванні піктограми подвійного дотику (з верхнього ряду сцени) над частиною подання, де слід було розпізнати подвійний дотик.
— Паулюс

1
@UIAdam за допомогою підкреслення для префікса приватного імені ivar в objc є досить поширеним, хоча ні? (походить із швидкого тла)
— Чарлтон Проватас

Відповіді:


412
UITapGestureRecognizer *singleTap = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doSingleTap)] autorelease];
singleTap.numberOfTapsRequired = 1; 
[self.view addGestureRecognizer:singleTap];

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

[singleTap requireGestureRecognizerToFail:doubleTap];

Примітка. Якщо ви користуєтесь numberOfTouchesRequired цим, це має бути .numberOfTouchesRequired = 1;

Для Свіфта

let singleTapGesture = UITapGestureRecognizer(target: self, action: #selector(didPressPartButton))
singleTapGesture.numberOfTapsRequired = 1
view.addGestureRecognizer(singleTapGesture)

let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(didDoubleTap))
doubleTapGesture.numberOfTapsRequired = 2
view.addGestureRecognizer(doubleTapGesture)

singleTapGesture.require(toFail: doubleTapGesture)

Дякуємо за відповідь, спробували ваш код, але він все ще не працює. Ще має бути щось, що я пропустив. У вас є ще якийсь натяк?
— Стенлі

чи можу я мати для цього файл вашої реалізації?
— Аніл Котарі

@Stanley: Відповідь Anils має спрацювати. Звичайно, ви також маєте надати обробників (doSingleTap, doDoubleTap)
— Rok Jarc

Один дотик оновлює UITableView, який працює як очікувалося. Наразі подвійне торкання просто виводить оператор журналу за допомогою NSLog. Я підозрюю, що статус першого респондента переходить від UIView до іншого місця після першого натискання, оскільки я нічого не робив явно щодо ланцюжка відповідей.
— Стенлі

6
Рішення працює для мене. Перемикач одного крана спрацьовує після деякої затримки.
— Володимир Обрізан

46

Рішення Swift 3:

let singleTap = UITapGestureRecognizer(target: self, action:#selector(self.singleTapAction(_:)))
singleTap.numberOfTapsRequired = 1
view.addGestureRecognizer(singleTap)

let doubleTap = UITapGestureRecognizer(target: self, action:#selector(self.doubleTapAction(_:)))
doubleTap.numberOfTapsRequired = 2
view.addGestureRecognizer(doubleTap)

singleTap.require(toFail: doubleTap)

У рядку коду singleTap.require (toFail: doubleTap) ми змушуємо один дотик зачекати і переконаємось, що подія tap не є подвійним натисканням.


31

Вам потрібно скористатися методом RequGestureRecognizerToFail:. Щось на зразок цього:

[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];


Спробували використовувати метод "Невдача" з обома розпізнавачами просто знову. Але все одно не працює. Якщо ви вже працювали з подвійним краном, будь ласка, поділіться зі мною ще трохи свого досвіду.
— Стенлі

1
Я спробував цей точний код (як і те, що більш детально розмістив Аніл), і він працює для мене.
— УІАдам

Дякую за коментар, тоді все одно має бути щось, що я пропустив зі свого боку ...
— Стенлі

Ваш код все ще псується із затримкамиTouches та чим іншим. Зробіть так, щоб він точно відповідав коду Аніла. Використовуйте лише RequGestureRecognizerToFail лише один раз, як ми це маємо.
— UIAdam

Зробимо так, як ви порадили пізніше сьогодні чи завтра, оскільки у мене зараз не вистачає часу. Дякую за добру допомогу ...
— Стенлі

15

// ---- по-перше, ви повинні виділити подвійний і одинарний жест ------- //

UITapGestureRecognizer* doubleTap = [[UITapGestureRecognizer alloc] initWithTarget : self action : @selector (handleDoubleTap:)];

UITapGestureRecognizer* singleTap = [[UITapGestureRecognizer alloc] initWithTarget : self action : @selector (handleSingleTap:)];

[singleTap requireGestureRecognizerToFail : doubleTap];
[doubleTap setDelaysTouchesBegan : YES];
[singleTap setDelaysTouchesBegan : YES];

// ----------------------- кількість крана ---------------- //

[doubleTap setNumberOfTapsRequired : 2];
[singleTap setNumberOfTapsRequired : 1];

// ------- додайте подвійне натискання та жест одним натисканням на вигляд або кнопку -------- //

[self.view addGestureRecognizer : doubleTap];
[self.view addGestureRecognizer : singleTap];

10

Не впевнений, що саме це ви шукаєте, але я робив поодинокі / подвійні натискання без розпізнавачів жестів. Я використовую його в UITableView, тому я використав цей код у методі didSelectRowAtIndexPath

    tapCount++;
    switch (tapCount)
    {
        case 1: //single tap
            [self performSelector:@selector(singleTap:) withObject: indexPath afterDelay: 0.2];
            break;
        case 2: //double tap
            [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(singleTap:) object:indexPath];
            [self performSelector:@selector(doubleTap:) withObject: indexPath];
            break;
        default:
            break;
    }
    if (tapCount>2) tapCount=0;

Методи singleTap і doubleTap просто недійсні, як параметр NSIndexPath:

- (void)singleTap:(NSIndexPath *)indexPath {
  //do your stuff for a single tap
}

- (void)doubleTap:(NSIndexPath *)indexPath {
  //do your stuff for a double tap
}

Сподіваюся, це допомагає


Дякую за відповідь, @Novarg. У вас виникли проблеми з розпізнавачами DoubleTap?
— Стенлі

@Stanley nope, SingleTap чекає 0,2 секунди перед стрільбою. І якщо в середній час був активований другий кран, то метод singleTap скасовується.
— Новарг

Це виглядає дуже перспективно, дякую за допомогу. Сьогодні знову закінчується час. Неодмінно спробую завтра :)
— Стенлі

Творча відповідь;)
— Майкл

дуже хороше рішення. Мені просто потрібно було додати tapCount = 0 на кожен обробник (singleTap, doubleTap), щоб переконатися, що наступні штрихи також розпізнаються.
— Сіріо

3

Рішення для Swift 2:

let singleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleSingleTap))
singleTapGesture.numberOfTapsRequired = 1 // Optional for single tap
view.addGestureRecognizer(singleTapGesture)

let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap))
doubleTapGesture.numberOfTapsRequired = 2
view.addGestureRecognizer(doubleTapGesture)

singleTapGesture.requireGestureRecognizerToFail(doubleTapGesture)

1

Я реалізував методи UIGestureRecognizerDelegate для виявлення як singleTap, так і doubleTap.

Просто зробіть це.

 UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleDoubleTapGesture:)];
    [doubleTap setDelegate:self];
    doubleTap.numberOfTapsRequired = 2;
    [self.headerView addGestureRecognizer:doubleTap];

    UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleSingleTapGesture:)];
    singleTap.numberOfTapsRequired = 1;
    [singleTap setDelegate:self];
    [doubleTap setDelaysTouchesBegan:YES];
    [singleTap setDelaysTouchesBegan:YES];
    [singleTap requireGestureRecognizerToFail:doubleTap];
    [self.headerView addGestureRecognizer:singleTap];

Потім реалізуйте ці делегатні методи.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
    return  YES;
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
    return YES;
}

0

У деяких представленнях є вбудовані розпізнавачі подвійного дотику ( MKMapViewє прикладом). Щоб обійти це, вам потрібно буде застосувати UIGestureRecognizerDelegateметод shouldRecognizeSimultaneouslyWithGestureRecognizerі повернути YES:

Спочатку реалізуйте свої подвійні та одинарні розпізнавачі:

// setup gesture recognizers
UITapGestureRecognizer* singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                action:@selector(mapViewTapped:)];
singleTapRecognizer.delegate = self;
singleTapRecognizer.numberOfTapsRequired = 1;


UITapGestureRecognizer* doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                      action:@selector(mapViewDoubleTapped:)];
doubleTapRecognizer.delegate = self;    // this allows
doubleTapRecognizer.numberOfTapsRequired = 2;
[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];

А потім реалізуйте:

#pragma mark UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer
*)otherGestureRecognizer {  return YES; }

-1

Посилаючись на коментар @ stanley -

Не намагайтеся використовувати жести дотику для вибору рядків для роботи, UITableViewоскільки він уже має повну обробку кран ....

Але ви повинні встановити "Скасувати дотики у перегляді" на "НІ" на ваших розпізнавальних пристроях жестів одного натискання, інакше вони ніколи не отримають події крана.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.