Захват и запись сенсорных событий в UIView

Я пытаюсь создать подкласс UIView и создать прозрачный вид. Это представление будет располагаться поверх многих других представлений, и его единственная задача — захватывать и записывать прикосновения пользователя (нажатие и панорамирование). Я пробовал много разных методов, объясненных в разных вопросах, заданных другими пользователями, но безуспешно. Это то, что я сделал до сих пор в своем файле реализации:

#import "touchLayer.h"

@implementation touchLayer

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) [self commonInit];
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) [self commonInit];
    return self;
}

- (void)commonInit
{
    self.userInteractionEnabled = YES;
    self.alpha = 0.0;
}

- (id)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    id hitView = [super hitTest:point withEvent:event];
    if (hitView == self)
    {
        UITouch *touch = [[event allTouches] anyObject];

        if (touch.phase == UITouchPhaseBegan) NSLog(@"touchesBegan");
        else if (touch.phase == UITouchPhaseMoved) NSLog(@"touchesMoved");
        else if (touch.phase == UITouchPhaseEnded) NSLog(@"touchesEnded");

        return nil;
    }
    else
        return hitView;
}

@end

Теперь этот код работает нормально, и я вижу касания в нижних слоях, но не могу различить touchBegan, touchMoved и touchEnded. [[event allTouches] anyObject] возвращает ноль. У вас есть идеи, как я могу захватить нажатие и панорамирование на UIView, не блокируя касания? Большое спасибо.


person Babak Samareh    schedule 05.11.2017    source источник
comment
Итак, теперь ваша проблема в том, что этот вид блокирует касания в представлении ниже. Это правильно?   -  person trungduc    schedule 05.11.2017
comment
На самом деле никакие касания не передаются нижнему виду. Однако мне нужно знать, какие касания (начало, перемещение, окончание) фиксируются этим UIView, но event.allTouches.anyObject возвращает nil.   -  person Babak Samareh    schedule 05.11.2017
comment
Насколько я знаю, я уверен, что прозрачный вид не получает прикосновения. Попробуйте дать ему цвет, и вы увидите разницу   -  person trungduc    schedule 05.11.2017
comment
Я также пробовал это с цветом и альфа-каналом. Он получает прикосновение, но, как я уже сказал, я не могу получить UITouchPhase. Это ноль.   -  person Babak Samareh    schedule 05.11.2017
comment
Попробуйте использовать эти 3 метода func touchesBegan(touches: NSSet, withEvent event: UIEvent) , func touchesMoved(touches: NSSet, withEvent event: UIEvent) и touchesEnd   -  person trungduc    schedule 05.11.2017
comment
Я также пробовал их, они правильно фиксируют касание, но не передают касание нижним представлениям. Я добавляю [super touchesBegan:touches withEvent:event];, чтобы отправить касание на следующий вид, не повезло.   -  person Babak Samareh    schedule 05.11.2017
comment
В двух словах, hitTest отлично отправляет тач в нижний вид, но не определяет тип тача, с другой стороны, touchesBegan, touchesMoved, ... правильно определяют тип тача, но не передают тач в нижний вид.   -  person Babak Samareh    schedule 05.11.2017


Ответы (1)


После расследования на самом деле я не могу найти решение для обнаружения касания с использованием метода hitTest с touchLayer. Но ваш вопрос касается захвата и записи прикосновений пользователя, поэтому у меня есть еще один вопрос по этому вопросу.

Мое решение

  • Подкласс UIWindow
  • Замените window из UIAppDelegate новым, созданным с помощью вашего класса окна.
  • Переопределите sendEvent метод UIWindow, захватите и запишите прикосновения пользователя в этом методе.

Это мой подкласс UIWindow для обнаружения касания. Я пробовал, и это работает.

@implementation DetectTouchWindow

- (void)sendEvent:(UIEvent *)event {
  UITouch *touch = [[event allTouches] anyObject];

  switch ([touch phase]) {
    case UITouchPhaseBegan:
      NSLog(@"Touch Began");
      break;
    case UITouchPhaseMoved:
      NSLog(@"Touch Move");
      break;
    case UITouchPhaseEnded:
      NSLog(@"Touch End");
      break;
    case UITouchPhaseCancelled:
      NSLog(@"Touch Cancelled");
      break;
    default:
      break;
  }

  [super sendEvent:event];
}

@end

Для более подробной и простой проверки я создал демо-репозиторий. Вы можете взглянуть на эту ссылку https://github.com/trungducc/stackoverflow/tree/recording-touch-events

Надеюсь это поможет ;)

person trungduc    schedule 06.11.2017
comment
Это здорово, большое спасибо, что поделились этим. Работает как шарм. - person Babak Samareh; 06.11.2017
comment
Добро пожаловать @BabakSamareh ;) - person trungduc; 06.11.2017
comment
Отдельно стоит отметить, что мне также приходится записывать касания в разных контроллерах представления. Этот метод, который вы предложили, начинает захват касаний с момента открытия приложения до его закрытия. Как я могу различать касания, захваченные для разных контроллеров представления? - person Babak Samareh; 06.11.2017
comment
Вы можете использовать UIApplication.sharedApplication.delegate.window.rootViewController, чтобы проверить текущий контроллер;) - person trungduc; 06.11.2017
comment
@BabakSamareh или в DetectTouchWindow просто используйте self.rootViewCont‌​roller - person trungduc; 06.11.2017
comment
Добро пожаловать, мой друг ;) - person trungduc; 06.11.2017
comment
Быстрый вопрос @trungduc, поскольку вы являетесь экспертом в UITouch, и, насколько мне известно, могу ли я каким-либо образом реализовать это в UIView? Это даст мне больше гибкости в том, чего я пытаюсь достичь. Есть ли метод sendEvent для UIView, который я могу использовать? Или любой другой способ захватить касание и панорамирование, а затем передать их в нижний вид? Я попробовал hitTest, но UIEvent, возвращаемый hitTest, не содержит информации о касании! - person Babak Samareh; 06.11.2017
comment
На ваш вопрос: 1. Есть ли метод sendEvent для UIView, который я могу использовать? - Боюсь, что ответ отрицательный, потому что sendEvent - это метод UIWindow, а не UIView. 2. Есть ли другой способ захватить касание и панорамирование, а затем передать их в нижний вид? - Я думаю, вы можете использовать UIGesture или touchBegin, touchMove без layerView ;) - person trungduc; 06.11.2017
comment
Разве они не блокируют касания? Например, если я переопределю touchesBegan, а затем коснусь UIButton, получит ли он касание? - person Babak Samareh; 06.11.2017
comment
Конечно, пусть попробует. Я думаю, что он все еще получает прикосновение. - person trungduc; 06.11.2017
comment
Я постараюсь обновить ответ здесь. Еще раз спасибо за ваше время и поддержку :) - person Babak Samareh; 06.11.2017