UITapGestureRecognizer 对动画子视图没有响应

Posted

技术标签:

【中文标题】UITapGestureRecognizer 对动画子视图没有响应【英文标题】:UITapGestureRecognizer not responding on animated subview 【发布时间】:2013-08-27 19:19:47 【问题描述】:

我有一个简单的程序,它可以创建一个子视图并在屏幕上设置动画。

作为该程序的一部分,我想在点击子视图时添加功能。我正在使用以下方法创建子视图,添加 UITapGestureRecognizer 然后为子视图设置动画:

int randomName = arc4random() % ([pieceNames count] - 1);
int animationDuration = arc4random() %  5 + 5 ;
NSString *randomPiece = [pieceNames objectAtIndex:randomName];

float yStart = arc4random() % 650;
float yEnd = arc4random() % 650;

UIView *piece = [[PieceView alloc]initWithFrame:CGRectMake(100.0, yStart, 75.0, 75.0)];
[piece setValue:randomPiece forKey:@"name"];

UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc]initWithTarget:self
                                                                            action:@selector(handleTouch:)];
[piece addGestureRecognizer:recognizer];

[[self view] addSubview:piece];

[UIView animateWithDuration:animationDuration
                      delay:0.0
                    options:UIViewAnimationOptionAllowUserInteraction
                 animations:^(void)
                     piece.center = CGPointMake(950.0, yEnd);
                  completion:^(BOOL done)
                     [piece removeFromSuperview];
                 ];

这是处理水龙头的代码:

PieceView *pv = (PieceView *) recognizer.view;
NSLog(@"%@ was tapped", pv.name);

当触摸 PieceView 时,程序没有响应会发生什么情况。但是,如果我删除动画块,那么程序会响应点击。

为什么UITapGestureRecognizer在动画时无法响应PieceView?

【问题讨论】:

您正试图在动画完成之前点击视图,对吗?因为否则视图显然不会响应,因为它不再位于视图层次结构中...... 【参考方案1】:

我在同样的问题上苦苦挣扎,归结为:动画视图只两个地方:起始位置和结束位置。 Core Animation 只是在一段时间内在起点和终点之间的插值位置渲染视图层。

这几乎就像当你仰望星空并意识到你所看到的并不是真正发生的事情现在。 :)

幸运的是,解决方案非常简单。您可以在超级视图上放置一个点击识别器,然后检查您的动画视图的presentationLayer(它确实在任何时间点都会为您提供准确的帧)以确定您的点击是否成功。

我构建了一个简单的UIViewController 来演示问题和解决方案:

#import <UIKit/UIKit.h>

@interface MSMViewController : UIViewController

@end

以及实现:

#import "MSMViewController.h"

@interface MSMViewController ()
@property (nonatomic, strong) UIView *animatedView;
@end

@implementation MSMViewController

- (void)viewDidLoad 
    [super viewDidLoad];

    CGRect startFrame = CGRectMake(125, 0, 70, 70);
    CGRect endFrame = CGRectMake(125, 400, 70, 70);

    // draw a box to show where the animated view begins
    UIView *startOutlineView = [[UIView alloc] initWithFrame:startFrame];
    startOutlineView.layer.borderColor = [UIColor blueColor].CGColor;
    startOutlineView.layer.borderWidth = 1;
    [self.view addSubview:startOutlineView];

    // draw a box to show where the animated view ends
    UIView *endOutlineView = [[UIView alloc] initWithFrame:endFrame];
    endOutlineView.layer.borderColor = [UIColor blueColor].CGColor;
    endOutlineView.layer.borderWidth = 1;
    [self.view addSubview:endOutlineView];

    self.animatedView = [[UIView alloc] initWithFrame:startFrame];
    self.animatedView.backgroundColor = [UIColor yellowColor];
    [self.view addSubview:self.animatedView];

    [UIView animateWithDuration:10 delay:2 options:UIViewAnimationOptionAllowUserInteraction animations:^

        self.animatedView.frame = endFrame;

     completion:nil];

    // this gesture recognizer will only work in the space where endOutlintView is
    UITapGestureRecognizer *boxTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(boxTap:)];
    [self.animatedView addGestureRecognizer:boxTap];

    // this one will work
    UITapGestureRecognizer *superviewTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(superviewTap:)];
    [self.view addGestureRecognizer:superviewTap];



- (void)boxTap:(UITapGestureRecognizer *)tap 
    NSLog(@"tap. view is at %@", NSStringFromCGPoint(self.animatedView.frame.origin));


- (void)superviewTap:(UITapGestureRecognizer *)tap 
    CGRect boxFrame = [self.animatedView.layer.presentationLayer frame];
    if (CGRectContainsPoint(boxFrame, [tap locationInView:self.view])) 
        NSLog(@"we tapped the box!");
    


@end

【讨论】:

感谢您的详细解释。【参考方案2】:

解决方案就简单多了,只需要设置动画的选项UIViewAnimationOptions.allowUserInteraction

UIView.animate(withDuration: duration, delay: 0.1, options: [.allowUserInteraction], animations: 
   ...
, completion:  (completed) in
   ...

【讨论】:

以上是关于UITapGestureRecognizer 对动画子视图没有响应的主要内容,如果未能解决你的问题,请参考以下文章

使用 UITapGestureRecognizer 无法识别的选择器

UIlabel 中的 UITapGestureRecognizer 错误

UITapGestureRecognizer 的问题

带有点击事件的 UITapGestureRecognizer

UIButton 上的 UITapGestureRecognizer

为啥 UIButton 会覆盖 UITapGestureRecognizer?