Функция распознавания жестов, прикрепленная к представлению контейнера, не блокирует событие касания кнопки в представлении контейнера, а блокирует событие касания кнопки панели инструментов
Таким образом, у меня есть контроллер представления, который имеет вид контейнера. В контейнерное представление встроен контроллер навигации, который также является родительским контроллером контроллера представления. Раскадровка выглядит так:
просмотр контроллера (mainViewController
) -> контроллер навигации -> просмотр контроллера (contentViewController
)
Вы можете увидеть скриншот раскадровки ниже.
Первая стрелка представляет собой переход от просмотра контейнера к контроллеру навигации. Вторая стрелка представляет собой отношение представляет contentViewController
является корневым контроллером представления навигационного контроллера.
mainViewController
а также contentViewController
объекты одного и того же класса, названные testViewController
, Это подкласс UIViewController. Его реализация проста. Всего три IBAction
методы, больше ничего. Вот код реализации:
#import "TestViewController.h"
@implementation TestViewController
- (IBAction)buttonTapped:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
message:@"button is tapped"
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
}
- (IBAction)barButtonTapped:(id)sender
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
message:@"bar button is tapped"
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
}
- (IBAction)viewTapped:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
message:@"view is tapped"
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles: nil];
[alert show];
}
@end
Я добавил Распознаватель жестов касания к представлению контейнера в mainViewController
, Отправляет viewTapped:(id)sender
сообщение для mainViewController
когда вид контейнера коснулся. Внутри корневой вид contentViewController
есть кнопка которая отправляет buttonTapped:(id)sender
сообщение для contentViewController
когда постучал. И есть панель кнопки на панели инструментов contentViewController
который отправляет barButtonTapped:(id)sender
сообщение для contentViewController
когда постучал. Начальная сцена mainViewController
, Когда приложение запущено, я обнаружил, что блокируются только события касания кнопки панели, событие касания обрабатывается кнопкой правильно. В документации Apple, регулирующей доставку штрихов к представлениям, говорится:
В простом случае, когда происходит касание, объект касания передается из объекта UIApplication в объект UIWindow. Затем окно сначала отправляет касания любым распознавателям жестов, прикрепленным к представлению, в котором произошли касания (или к суперпредставлениям этого представления), прежде чем оно передает касание самому объекту представления.
Я думал, что сенсорное событие не перейдет на кнопку. Это действительно смутило меня. Может кто-нибудь объяснить это поведение? Большое спасибо.
Снимок экрана раскадровки:
1 ответ
Руководство по обработке событий для iOS: доставка событий: раздел "Сеть ответчика следует по определенному пути доставки" в разделе "Ответчик" описывает, как события касания передаются сначала в касание, которое было затронуто, затем вверх по всем его суперпредставлениям, а затем в окно, и, наконец, к самому приложению.
Упрощенное представление иерархии представления вашего проекта будет:
mainViewController's Root View
| mainViewController's Container View (has Tap Gesture Recognizer)
| | UINavigationController's Root View
| | | contentViewController's View
| | | | UIButton ("Button")
| | | UINavigationController's Toolbar View
| | | | UIToolbarTextButton ("Item")
... поэтому, когда вы нажимаете кнопку или кнопку панели инструментов, они получают сенсорное событие перед представлением контейнера mainViewController.
Причина, по которой происходит событие кнопки, а кнопки панели инструментов, по-видимому, связана с разделом "Руководство по обработке событий для iOS": раздел "Взаимодействие с другими элементами управления пользовательского интерфейса" распознавателей жестов:
В iOS 6.0 и позже, управляющие действия по умолчанию предотвращают перекрывающееся поведение распознавателя жестов. Например, действие по умолчанию для кнопки - одно нажатие. Если у вас есть распознаватель жестов с одним касанием, прикрепленный к родительскому представлению кнопки, и пользователь нажимает кнопку, то метод действия кнопки получает событие касания вместо распознавателя жестов.
Это объясняет, почему UIButton
в состоянии опередить распознаватель жестов касания, но он ничего не говорит о кнопке панели инструментов.
Если вы распечатаете иерархию видов, то увидите, что кнопка панели инструментов представлена с помощью UIToolbarButton
который является частным классом, который наследует непосредственно от UIControl
, Исходя из наших наблюдений, мы предположили бы, что UIToolbarButton
не вытесняет распознаватели жестов, как публика UIControl
подклассы делают. Когда я залил его touchesCancelled:withEvent:
Я обнаружил, что метод вызывается после срабатывания распознавателя жестов касания, что, по-видимому, и следовало ожидать на основании Руководства по обработке событий для iOS: раздел "Распознаватели жестов" в разделе "Распознаватели жестов" получает первую возможность распознать касание ", где они отмечают:
... если распознаватель жестов распознает сенсорный жест, то окно никогда не доставляет сенсорный объект в вид, а также отменяет любые сенсорные объекты, которые он ранее отправил в вид, которые были частью этой распознанной последовательности.
Есть несколько разных способов изменить это поведение, и выбор будет зависеть от вашей конечной цели. Если вы хотите разрешить касания на панели инструментов, вы можете проверить, если UITouch
отправлено делегату распознавателя жестов gestureRecognizer:shouldReceiveTouch:
был внутри рамки панели инструментов и вернуться NO
если бы это было Блокировка касается UIButton
в частности, вероятно, потребуется подкласс, но если вы хотите заблокировать все прикосновения к контроллерам дочернего представления mainViewController, вы можете добавить прозрачное представление к его представлению контейнера.