UIGestureRecognizer блокирует subview для обработки событий касания
Я пытаюсь понять, как это делается правильно. Я попытался изобразить ситуацию:
![enter image description here]()
Я добавляю UITableView
как подпункт UIView
. UIView
отвечает на tap- и pinchGestureRecognizer
, но при этом tableview перестает реагировать на эти два жестов (он все еще реагирует на swipes).
Я сделал это для работы со следующим кодом, но это, очевидно, не очень хорошее решение, и я уверен, что есть лучший способ. Это помещается в UIView
(супервизор):
-(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];
}
Ответы
Ответ 1
У меня была очень похожая проблема и я нашел свое решение в этом вопросе SO. В общем, назначьте себя как делегат для своего UIGestureRecognizer
, а затем проверьте целевое представление, прежде чем разрешить распознавателю обрабатывать мелодию. Соответствующий метод делегата:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch
Ответ 2
Блокировка событий касания к подзонам является поведением по умолчанию. Вы можете изменить это поведение:
UITapGestureRecognizer *r = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(agentPickerTapped:)];
r.cancelsTouchesInView = NO;
[agentPicker addGestureRecognizer:r];
Ответ 3
Одна из возможностей заключается в подклассе вашего распознавателя жестов (если вы еще этого не сделали) и переопределите -touchesBegan:withEvent:
, чтобы он определял, началось ли каждое касание в исключенном подзоне и вызывает -ignoreTouch:forEvent:
для этого касания, если это так.
Очевидно, вам также нужно добавить свойство, чтобы отслеживать исключенный subview или, возможно, лучше, массив исключенных subviews.
Ответ 4
Я показывал раскрывающийся список, который имел свой собственный tableview. В результате touch.view
иногда возвращал классы типа UITableViewCell
. Мне пришлось пройти через суперкласс (ы), чтобы убедиться, что это был подкласс, который, как я думал, был:
-(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
Можно обойтись без наследования любого класса.
вы можете проверить gestureRecognizers в селекторе обратного вызова жестов
если view.gestureRecognizers не содержит ваш gestureRecognizer, просто игнорируйте его
например
- (void)viewDidLoad
{
UITapGestureRecognizer *singleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
singleTapGesture.numberOfTapsRequired = 1;
}
проверить view.gestureRecognizers здесь
- (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
}
}
Ответ 6
Я создал подкласс UIGestureRecognizer, предназначенный для блокировки всех распознавателей жестов, прикрепленных к супервизорам определенного вида.
Это часть моего проекта WEPopover. Вы можете найти здесь здесь.
Ответ 7
Основываясь на @Pin Shih Wang answer. Мы игнорируем все краны, отличные от тех, которые отображаются в представлении, содержащем распознаватель жестов. Все метчики перенаправляются в иерархию представлений как обычно, как мы установили tapGestureRecognizer.cancelsTouchesInView = false
. Вот код в 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)
}
}
Ответ 8
Вы можете отключить его и включить.... в моем коде я сделал что-то вроде этого, поскольку мне нужно было отключить его, когда клавиатура не показывалась, вы можете применить его к своей ситуации:
вызов this is viewdidload и т.д.:
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(notifyShowKeyboard:) name:UIKeyboardDidShowNotification object:nil];
[center addObserver:self selector:@selector(notifyHideKeyboard:) name:UIKeyboardWillHideNotification object:nil];
затем создайте два метода:
-(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
}
То, что это делает, отключает краны. Я должен был включить tap в переменную экземпляра и освободить его в dealloc, хотя.
Ответ 9
Я тоже делал popover, и вот как я это сделал
func didTap(sender: UITapGestureRecognizer) {
let tapLocation = sender.locationInView(tableView)
if let _ = tableView.indexPathForRowAtPoint(tapLocation) {
sender.cancelsTouchesInView = false
}
else {
delegate?.menuDimissed()
}
}
Ответ 10
реализовать делегат для всех распознавателей parentView и поместить метод gesureRecognizer в делегат, который отвечает за одновременный запуск распознавателей:
func gestureRecognizer(UIGestureRecognizer, shouldBeRequiredToFailByGestureRecognizer:UIGestureRecognizer) -> Bool {
if (otherGestureRecognizer.view.isDescendantOfView(gestureRecognizer.view)) {
return true
} else {
return false
}
}
U может использовать методы сбоя, если вы хотите, чтобы дети запускались, но не родительские распознаватели:
https://developer.apple.com/reference/uikit/uigesturerecognizerdelegate