Как заставить степпер и длинное нажатие сосуществовать?

Я попытался настроить представление с помощью жеста длительного нажатия и степпера, настроенного на непрерывные обновления. При длительном нажатии непрерывная функция степпера не возникает. На данный момент я отключил долгое нажатие. Думаю, мне это не нужно. Но для справки в будущем, как я могу позволить им сосуществовать?

Просто для ясности, вот как был настроен экран, когда я пробовал это.

  • Приложение было настроено с помощью простого контроллера представления.
  • К этому представлению было добавлено подвид (может быть контроллер, но я просто сделал его UIView).
  • В это подпредставление были добавлены несколько меток и степпер.
  • Степперы были подключены как выходы и действия.
  • В основной вид в IB добавлен распознаватель длинных нажатий.
  • Для полноты в основной вид в IB также был добавлен жест касания.

Нажатия на функцию основного вида, как и ожидалось. Нажатия на степперы работают как положено. Длительное нажатие на главном экране работает, как и ожидалось. Лонгпресс на степпере не дает.

Я изменил код, вызываемый длительным нажатием, чтобы проверить кадр подпредставления и не действовать, если место касания было внутри этого прямоугольника, но это не имело значения. Я не пытался добиться отказа длинного нажатия в этой ситуации, но, полагаю, я попробую это в следующий раз. РЕДАКТИРОВАТЬ: Хорошо, может быть, нет. Кажется, для этого нет API. Однако есть этот кладж, который я не собираюсь попробовать.

Прилагается снимок экрана из профилировщика с перевернутым деревом вызовов, чтобы вы могли видеть, чем вызывается каждый элемент.

darkStepped: — это IBAction, который вызывается степпером. Если бы степпер запускался распознавателем жестов, разве я не ожидал бы увидеть распознаватель жестов в дереве вызовов?

Снимок экрана степпера, показывающий раздел, вызываемый удерживанием степпера


person Victor Engel    schedule 30.12.2013    source источник
comment
пожалуйста, предоставьте код, чтобы было понятнее, что вы пытаетесь сделать...   -  person sergio    schedule 31.12.2013
comment
Не уверен, какой код включать. У степпера нет кода, кроме IBAction, который работает при тапе, но не при удержании. Длинное нажатие — это жест длительного нажатия, перетаскиваемый в IB. Когда убираю лонгпресс в ИБ, степпер работает в непрерывном режиме. Я не думаю, что проблема в моем коде, а в знании того, какая деятельность происходит за кулисами со степпером. Например, использует ли степпер распознаватель жестов длительного нажатия, который конфликтует с длинным нажатием моего представления?   -  person Victor Engel    schedule 31.12.2013


Ответы (2)


Если бы степпер запускался распознавателем жестов, разве я не ожидал бы увидеть распознаватель жестов в дереве вызовов?

Трассировка стека показывает, что метод _updateCount шагового двигателя запускается через таймер.

Это может быть связано с тем, что степпер имеет режим «автоинкремент», в котором, пока вы держите его нажатым, он будет обновляться с заданной (переменной) скоростью. Таким образом, вместо простого вызова _updateCount степпер устанавливает таймер для обработки такого поведения.

По какой бы причине ни использовался таймер, он объясняет, почему вы не видите распознаватель жестов в трассировке стека.

В вашем случае происходит то, что степпер получает прикосновения, обрабатывает их и не перенаправляет их на какие-либо подключенные к нему распознаватели жестов.

Это можно объяснить следующим образом, хотя в этом фрагменте явно не упоминается распознаватель длительного нажатия по отношению к элементу управления UIStepper:

Согласно Apple Docs:

Взаимодействие с другими элементами управления пользовательского интерфейса В iOS 6.0 и более поздних версиях действия элементов управления по умолчанию предотвращают перекрытие поведения распознавателя жестов. Например, действие по умолчанию для кнопки — одно касание. Если у вас есть распознаватель жестов одиночного касания, прикрепленный к родительскому представлению кнопки, и пользователь нажимает кнопку, то метод действия кнопки получает событие касания вместо распознавателя жестов. Это относится только к распознаванию жестов, которое перекрывает действие по умолчанию для элемента управления, в том числе:

Одно нажатие одним пальцем на UIButton, UISwitch, UIStepper, UISegmentedControl и UIPageControl.

...

Если у вас есть собственный подкласс одного из этих элементов управления и вы хотите изменить действие по умолчанию, прикрепите распознаватель жестов непосредственно к элементу управления, а не к родительскому представлению. Затем распознаватель жестов сначала получает событие касания. Как всегда, обязательно ознакомьтесь с Руководством по человеческому интерфейсу iOS, чтобы убедиться, что ваше приложение предлагает интуитивно понятный пользовательский интерфейс, особенно при переопределении поведения стандартного элемента управления по умолчанию.

Итак, кажется, вы можете прикрепить распознаватель жестов непосредственно к элементу управления (возможно, вам нужно создать подкласс UIStepper, чтобы это работало, я не совсем уверен, как интерпретировать последний абзац). Будем надеяться, что это не отключит базовую работу степпера (но, возможно, так и будет).

person sergio    schedule 31.12.2013
comment
Выходные соединения, Распознаватели жестов не выбраны. Похоже, что никакие распознаватели жестов не видны таким образом. Я думал об использовании gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:, но я не знаю, как получить доступ к распознавателю жестов степпера. - person Victor Engel; 31.12.2013
comment
вы должны проверить свой выход UIStepper программно, чтобы увидеть, имеет ли его свойство gestureRecognizers какое-либо содержимое... не из Interface Builder... - person sergio; 31.12.2013
comment
Хм. Я попробую это. Тем временем я вставил снимок экрана из профилировщика, показывающий дерево вызовов. Я удивлен, что не вижу там ничего похожего на распознаватель жестов. - person Victor Engel; 31.12.2013
comment
sender.gestureRecognizers равно нулю (sender — это шаговый объект). - person Victor Engel; 31.12.2013
comment
Я понимаю. Пожалуйста, проверьте мой отредактированный ответ. Этот случай явно упоминается в документах Apple. - person sergio; 31.12.2013
comment
Не уверен, что это связано, но есть свойство viewFlags, которое включает два значения, gesturesEnabled и deliversTouchesForGesturesToSuperview, оба ДА. - person Victor Engel; 31.12.2013
comment
Я не думаю, что новый ответ касается моей проблемы. Я отредактирую свой вопрос, чтобы быть более ясным. - person Victor Engel; 31.12.2013
comment
Это viewFlags позволит думать, что супервизор будет обрабатывать прикосновения через распознаватели жестов, хотя в ваших тестах это не так... - person sergio; 31.12.2013
comment
В ответ на ваш отредактированный ответ: да, степпер по умолчанию реагирует на длительное нажатие, обновляя примерно раз в секунду в течение некоторого времени, а затем чаще по прошествии времени. Я согласен, что, вероятно, для этого и нужен таймер. Техника добавления распознавателя к элементу управления выполняет противоположное тому, что я пытаюсь сделать (получение распознавателя жестов в родительском представлении для запуска перед элементом управления). Я хочу, чтобы элемент управления распознавал свой жест вместо распознавателя в родительском представлении. Я предполагаю, что это не работает, потому что длительное нажатие НЕ является жестом по умолчанию. Это будет соответствовать документу, который вы цитируете - person Victor Engel; 31.12.2013
comment
Чтобы степпер получал касания, вы установили cancelsTouchesInView распознавателя жестов родительского вида на NO? - person sergio; 31.12.2013

Еще раз внимательно изучив документы Apple, я нашел решение. Я добавил контроллер представления в качестве делегата к распознавателю жестов длительного нажатия.

self.longPress.delegate = self;

(и, конечно же, добавление <UIGestureRecognizerDelegate> в интерфейс, а затем добавление этого метода во вью-контроллер:

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
   // Determine if the touch is inside the custom subview
   if (gestureRecognizer == self.longPress) {
      CGPoint touchLocation = [touch locationInView:self.view];
      if (CGRectContainsPoint(self.antControl.frame, touchLocation)) {
         return NO;
      }
   }
   return YES;
}

Таким образом, распознаватель жестов даже не вызывается, когда длительное нажатие происходит в кадре self.antControl, который является подвидом, упомянутым в вопросе.

person Victor Engel    schedule 31.12.2013