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.