[英]UITapGestureRecognizer not responding on animated subview
I have a simple program that creates a subview and animates it across the screen. 我有一个简单的程序,可以创建一个子视图并在屏幕上设置动画。
As part of this program, I would like to add functionality when the subview is tapped. 作为该程序的一部分,我想在点击子视图时添加功能。 I am using the following method to create the subview, add the UITapGestureRecognizer and then animate the subview:
我使用以下方法创建子视图,添加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];
}];
Here is the code that handles the tap: 以下是处理点按的代码:
PieceView *pv = (PieceView *) recognizer.view;
NSLog(@"%@ was tapped", pv.name);
What happens is when a PieceView is touched the program does not respond. 触摸PieceView时程序没有响应会发生什么。 However, if I remove the animation block then the program responds to the tap.
但是,如果我删除动画块,则程序会响应该点击。
Why does the UITapGestureRecognizer fail to respond to PieceView when it is animated? 为什么UITapGestureRecognizer在动画时无法响应PieceView?
I struggled with this same problem, and it boils down to this: the animated view only ever is in two places: the starting position, and the ending position. 我有同样的问题挣扎,并把它归结为一点:动画视图永远只能是在两个地方:起始位置和结束位置。 Core Animation simply renders the view's layer in interpolated positions between the start and end points over a period of time.
核心动画只需在一段时间内在起点和终点之间的插值位置渲染视图的图层。
It's almost like when you look to the stars and realize that what you see is not actually what is happening right now . 这几乎是当你看看星星,并认识到你所看到的实际上不是现在发生的事情一样。 :)
:)
Luckily, the solution is pretty simple. 幸运的是,解决方案非常简单。 You can put a tap recognizer on the superview and then inspect your animated view's
presentationLayer
(which does give you an accurate frame at any point in time) to determine if your tap is a hit or not. 您可以在超级视图上放置一个水龙头识别器,然后检查您的动画视图的
presentationLayer
(它可以在任何时间点为您提供准确的帧),以确定您的点击是否是一个命中。
I've built a simple UIViewController
that demonstrates both the problem and solution: 我已经构建了一个简单的
UIViewController
来演示问题和解决方案:
#import <UIKit/UIKit.h>
@interface MSMViewController : UIViewController
@end
And the implementation: 并实施:
#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
The solution is much simpler, you just need to set the animation's option UIViewAnimationOptions.allowUserInteraction . 解决方案要简单得多,您只需要设置动画的选项UIViewAnimationOptions.allowUserInteraction 。
UIView.animate(withDuration: duration, delay: 0.1, options: [.allowUserInteraction], animations: {
...
}, completion: { (completed) in
...
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.