【问题标题】:How can I shorten the time "delayTouchesBegan" delays touchesBegan?如何缩短“延迟 TouchesBegan”延迟 touchesBegan 的时间?
【发布时间】:2014-01-04 20:02:34
【问题描述】:

在我的一个视图控制器中,我有几个包含 UITapGestureRecognizer 的视图,以及 touchesBegan 的实现。我需要优先于touchesBegan,因此我将手势识别器的delaysTouchesBegan 属性设置为YES。这可以正常工作,但有一个问题:手势识别器延迟 touchesBegan 太久。根据documentation

当属性值为YES时,窗口暂停将UITouchPhaseBegan阶段的触摸对象传递给视图。如果手势识别器随后识别出其手势,则丢弃这些触摸对象。但是,如果手势识别器无法识别其手势,则窗口会在 touchesBegan:withEvent: 消息中将这些对象传递给视图(可能还有后续的 touchesMoved:withEvent: 消息以通知它触摸的当前位置) .

问题基本上是当手势识别器无法识别手势并将这些对象传递给touchesBegan时,该操作需要太长时间。有没有办法加快它,或者只是为了确定它是否是点击而对手势的处理是密集的并且不可能缩短?


编辑:

这里有更多信息。这是我用来设置手势识别器的代码:

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];

【问题讨论】:

  • 有更新你的答案请关注
  • 虽然它可能不适用于您的项目,但在另一个视图之前拦截来自一个视图的触摸的简单方法是实现子视图 hitTest(即- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
  • @qegal 你没有发现我的回答有用吗?
  • @Sha - 抱歉,我太忙了,无法测试它。到目前为止,这似乎是最好的答案,所以我会给你赏金。

标签: ios iphone objective-c uitapgesturerecognizer touchesbegan


【解决方案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: 以查看它被调用的确切时间)。例如,如果您用UITapGestureRecognizer 触摸UIView 并且不移动手指,点击识别器仍然认为您有可能在相同位置抬起手指,这将被识别为点击。所以它会一直等到你平移手指或抬起它。另一方面,如果您立即平移,则 UIView 几乎不会延迟发送到-touchesBegan:withEvent:

    您可以尝试的解决方法是:

    1. 请改用手势识别器的 cancelTouchesInView 属性。如果您将其设置为YES,则UIView 将立即处理触摸,然后如果手势识别器最终将触摸识别为手势,则会发送视图-touchesCancelled:withEvent:,您可以在其中回滚您所做的任何更改制作。

    2. UIView 中使用cancelTouchesInViewNSTimer。在UIView-touchesBegan:withEvent: 中启动NSTimer,当它触发时,对视图执行您的操作。如果视图在定时器触发之前被发送到-touchesCancelled:withEvent:,请取消定时器。

    3. 子类UIGestureRecognizer 并实现您自己的点击识别器:)

    我制作了选项 1 和 2 的示例。该示例有一个可以在屏幕上拖动的视图,并且该视图有一个可以更改视图颜色的点击识别器。如果您点击视图但在释放之前稍微拖动它,您会看到“回滚”将视图捕捉到触摸之前的位置。如果将JCPanningViewdelayResponseToTouch 设置为YES,则在延迟期内看不到任何拖动。

    这可能对您有用,也可能对您无效,具体取决于您的 UIViews 处理他们的触摸的方式。

    这是视图控制器的界面 (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's 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】:

      为此,当您需要延迟触摸的视图被点击时,您可以启动一个具有所需时间的计时器,一旦时间完成,您就可以调用所需的方法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-21
        • 1970-01-01
        • 1970-01-01
        • 2011-03-06
        相关资源
        最近更新 更多