Как я могу сократить время "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
Для этого, когда ваше изображение прослушивается, на которое вы должны задержать прикосновение, вы можете запустить таймер с нужным временем, и по истечении времени вы можете вызвать нужный вам метод.