Как я могу сократить время "delayTouchesBegan" задерживает TouchBegan?

В одном из моих контроллеров представления у меня есть несколько представлений, содержащих UITapGestureRecognizer, а также реализацию touchesBegan. Мне нужно расставить приоритеты над клавишами touchesBegan, поэтому я устанавливаю свойство delaysTouchesBegan распознавателей жестов на YES. Это работает правильно, но есть одна проблема: распознаватель жестов слишком долго задерживает touchesBegan. Согласно documentation:

Когда значение свойства равно YES, окно приостанавливает доставку сенсорных объектов на фазе UITouchPhaseBegan к представлению. Если распознаватель жеста впоследствии распознает его жест, эти сенсорные объекты отбрасываются. Если распознаватель жестов, однако, не распознает его жест, окно передает эти объекты в представление в сообщении touchsBegan: withEvent: message (и, возможно, последующие сообщенияMoved: withEvent: message, чтобы информировать его о текущих местоположениях).

В основном проблема заключается в том, что, когда распознаватель жестов не распознает жест и доставляет эти объекты до touchesBegan, эта операция занимает слишком много времени. Есть ли способ ускорить его, или это просто, что обработка жеста, чтобы определить, является ли это краном интенсивным и невозможно сократить?


Edit:

Вот еще информация. Это код, который я использую для настройки распознавателя жестов:

UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
tapRecognizer.cancelsTouchesInView = NO;
tapRecognizer.delaysTouchesBegan = YES;
tapRecognizer.delegate = self;
tapRecognizer.numberOfTapsRequired = 1;
tapRecognizer.numberOfTouchesRequired = 1;
[self.someView addGestureRecognizer:tapRecognizer];

Ответы

Ответ 1

Я бы решил это с изменением UITapGestureRecognizer на UILongPressGestureRecognizer. Название этих двух немного вводит в заблуждение, но с UILongPressGestureRecognizer вы можете установить minimumPressDuration:

Пальцы минимального периода должны нажимать на вид для быть признанным.

UILongPressGestureRecognizer *tapRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
tapRecognizer.delegate = self;
tapRecognizer.minimumPressDuration = //Up to you;
[self.someView addGestureRecognizer:tapRecognizer];

Ответ 2

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

Задержка, по-видимому, зависит от того, сколько времени потребуется для обработки жестов, так что да, ее невозможно настроить (вы можете входить в журнал -touchesBegan:withEvent:, чтобы видеть, когда он вызывается). Например, если вы коснетесь UIView с помощью UITapGestureRecognizer и не двигаете пальцем, распознающее устройство по-прежнему считает, что вы поднимете свой палец в том же положении, которое будет распознано как кран. Поэтому он будет продолжать ждать, пока вы не закроете палец или не поднимете его. С другой стороны, если вы скопируете немедленно, UIView отправляется -touchesBegan:withEvent: с почти никакой задержкой.

Обходные пути, которые вы можете попробовать:

  • Вместо этого используйте свойство распознавателя жестов cancelTouchesInView. Если вы установите значение YES, то UIView будет обрабатывать штрихи сразу, а затем, если распознаватель жестов в конечном итоге распознает штрихи в качестве жестов, открывается сообщение -touchesCancelled:withEvent:, где вы можете отменить любые изменения, которые вы сделал.

  • Используйте cancelTouchesInView с NSTimer в UIView. Запустите NSTimer в UIView -touchesBegan:withEvent:, и когда он срабатывает, выполните свое действие в представлении. Если представление отправляется -touchesCancelled:withEvent: до срабатывания таймера, отмените таймер.

  • Подкласс UIGestureRecognizer и реализовать свой собственный распознаватель отводов:)

Я привел пример вариантов 1 и 2. В примере есть представление, которое вы можете перетаскивать по экрану, а в представлении есть распознающий кран, который изменяет цвет представления. Если вы коснетесь взгляда, но немного перетащите его перед выпуском, вы увидите, что "откат" привязывает представление к его позиции до касания. Если вы установите для параметра JCPanningView delayResponseToTouch значение YES, вы не увидите перетаскивание в течение периода задержки.

Это может работать или не работать для вас в зависимости от того, как ваш UIView обрабатывает свои прикосновения.

Вот интерфейс контроллера представления (JCGestureViewController.h):

#import <UIKit/UIKit.h>

@interface JCGestureViewController : UIViewController
@end

@interface JCPanningView : UIView
@property (nonatomic) BOOL delayResponseToTouch;
- (void)changeColor;
@end

и реализация (JCGestureViewController.m):

#import "JCGestureViewController.h"

@interface JCGestureViewController ()
@property (strong, nonatomic) JCPanningView *panningView;
@end

@implementation JCGestureViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    _panningView = [[JCPanningView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 200.0f, 200.0f)];
    [self.view addSubview:_panningView];

    UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                    action:@selector(tappedPanningView)];
    tapRecognizer.cancelsTouchesInView = YES;
    [_panningView addGestureRecognizer:tapRecognizer];

    // set this to YES to have a timer delay the view response to touches
    _panningView.delayResponseToTouch = NO;
}

- (void)tappedPanningView
{
    [self.panningView changeColor];
}

@end

@interface JCPanningView ()

@property (nonatomic) CGPoint touchBeganLocation;
@property (nonatomic) CGPoint centerWhenTouchBegan;
@property (nonatomic) BOOL respondToTouches;
@property (nonatomic) NSTimer *timer;

@end

@implementation JCPanningView

- (void)dealloc
{
    if (_timer) {
        [_timer invalidate];
        _timer = nil;
    }
}

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

- (void)changeColor
{
    self.backgroundColor = [self randomColor];
}

- (CGFloat)randomRGBValue
{
    return (arc4random() % 255) / 255.0f;
}

- (UIColor *)randomColor
{
    return [UIColor colorWithRed:[self randomRGBValue] green:[self randomRGBValue] blue:[self randomRGBValue] alpha:1.0f];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touchesBegan:");
    [super touchesBegan:touches withEvent:event];

    UITouch *touch = [touches anyObject];
    self.touchBeganLocation = [touch locationInView:self.superview];
    self.centerWhenTouchBegan = self.center;

    if (self.delayResponseToTouch) {
        if (self.timer) {
            [self.timer invalidate];
        }
        self.timer = [NSTimer scheduledTimerWithTimeInterval:0.2
                                                      target:self
                                                    selector:@selector(startRespondingToTouches)
                                                    userInfo:nil
                                                     repeats:NO];
    }
}

- (void)startRespondingToTouches
{
    self.respondToTouches = YES;
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    self.center = self.centerWhenTouchBegan;

    if (self.timer) {
        [self.timer invalidate];
        self.timer = nil;
    }

    if (self.delayResponseToTouch) {
        self.respondToTouches = NO;
    }
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesMoved:touches withEvent:event];

    if (self.delayResponseToTouch && !self.respondToTouches) {
        return;
    }

    UITouch *touch = [touches anyObject];
    CGPoint newLocation = [touch locationInView:self.superview];
    CGPoint delta = CGPointMake(newLocation.x - self.touchBeganLocation.x, newLocation.y - self.touchBeganLocation.y);
    self.center = CGPointMake(self.centerWhenTouchBegan.x + delta.x, self.centerWhenTouchBegan.y + delta.y);
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (self.delayResponseToTouch) {
        self.respondToTouches = NO;
    }
}

@end

Ответ 3

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