iOS视图移动时为什么不能触发事件
Why can't the event be triggered when the iOS view moves
我测试过了。当我移动视图时,视图上的点击事件没有响应,只有在停止时才响应。我不知道为什么会这样。下面是我的代码
@interface ViewController ()
@property(nonatomic,strong)UIView *testView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.testView = [[UIView alloc]init];
self.testView.backgroundColor = [UIColor redColor];
self.testView.frame = CGRectMake(0, 100, 100, 100);
[self.view addSubview:self.testView];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapTestView:)];
[self.testView addGestureRecognizer:tap];
}
- (void)tapTestView:(UITapGestureRecognizer *)tap {
NSLog(@"Event triggered");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[UIView animateWithDuration:6 animations:^{
CGRect frame = self.testView.frame;
frame.origin.x = 400;
self.testView.frame = frame;
}];
}
首先,您要确保使用 animatewithduration:delay:options:animations:completion:
with the UIViewAnimationOptionAllowUserInteraction
选项。如果不使用此选项,动画视图将不会接收到触摸。
[UIView animateWithDuration:26 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
CGRect frame = self.testView.frame;
frame.origin.x = ...;
self.testView.frame = frame;
} completion:nil];
其次,当视图被动画化时,如果您在移动时检查该视图的 frame
,您会发现 frame
属性 不会反映视图确实是在那一刻,而是它最终会在哪里。具体来说,frame
属性 将是您在 animations
块中设置的值,即使它还没有真正移动到那里。
此行为的含义是,即使您在动画期间启用用户交互(如上所示),也会根据视图的最终目的地而不是现在的位置来识别手势。例如,如果您开始从矩形 A 到矩形 B 的帧动画,手势识别器将识别矩形 B 内的点击,即使视图还不存在!相反,它不会识别动画视图恰好所在的点击,因为 frame
实际上认为视图已经在目的地。
为了解决这个问题,必须参考视图层的 presentationLayer
来获取视图中间动画的位置。一种方法是向主视图添加手势识别器,然后在其中查看触摸是否在动画视图的表示层内:
- (void)tapMainView:(UITapGestureRecognizer *)tap {
CGPoint point = [tap locationInView:self.testView.superview];
CGRect frame = self.testView.layer.presentationLayer.frame;
BOOL isInTestView = CGRectContainsPoint(frame, point);
if (isInTestView) {
[self testViewAction];
return;
}
// otherwise, we're in the super view
[self mainViewAction];
}
或者,您可以 (a) 为子视图定义一个 UIView
子类,并且 (b) 覆盖其 hitTest
实现以考虑表示层:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if ([self.layer.presentationLayer hitTest:[self convertPoint:point toView:self.superview]]) {
return self;
} else {
return nil;
}
}
我测试过了。当我移动视图时,视图上的点击事件没有响应,只有在停止时才响应。我不知道为什么会这样。下面是我的代码
@interface ViewController ()
@property(nonatomic,strong)UIView *testView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.testView = [[UIView alloc]init];
self.testView.backgroundColor = [UIColor redColor];
self.testView.frame = CGRectMake(0, 100, 100, 100);
[self.view addSubview:self.testView];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapTestView:)];
[self.testView addGestureRecognizer:tap];
}
- (void)tapTestView:(UITapGestureRecognizer *)tap {
NSLog(@"Event triggered");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[UIView animateWithDuration:6 animations:^{
CGRect frame = self.testView.frame;
frame.origin.x = 400;
self.testView.frame = frame;
}];
}
首先,您要确保使用 animatewithduration:delay:options:animations:completion:
with the UIViewAnimationOptionAllowUserInteraction
选项。如果不使用此选项,动画视图将不会接收到触摸。
[UIView animateWithDuration:26 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
CGRect frame = self.testView.frame;
frame.origin.x = ...;
self.testView.frame = frame;
} completion:nil];
其次,当视图被动画化时,如果您在移动时检查该视图的 frame
,您会发现 frame
属性 不会反映视图确实是在那一刻,而是它最终会在哪里。具体来说,frame
属性 将是您在 animations
块中设置的值,即使它还没有真正移动到那里。
此行为的含义是,即使您在动画期间启用用户交互(如上所示),也会根据视图的最终目的地而不是现在的位置来识别手势。例如,如果您开始从矩形 A 到矩形 B 的帧动画,手势识别器将识别矩形 B 内的点击,即使视图还不存在!相反,它不会识别动画视图恰好所在的点击,因为 frame
实际上认为视图已经在目的地。
为了解决这个问题,必须参考视图层的 presentationLayer
来获取视图中间动画的位置。一种方法是向主视图添加手势识别器,然后在其中查看触摸是否在动画视图的表示层内:
- (void)tapMainView:(UITapGestureRecognizer *)tap {
CGPoint point = [tap locationInView:self.testView.superview];
CGRect frame = self.testView.layer.presentationLayer.frame;
BOOL isInTestView = CGRectContainsPoint(frame, point);
if (isInTestView) {
[self testViewAction];
return;
}
// otherwise, we're in the super view
[self mainViewAction];
}
或者,您可以 (a) 为子视图定义一个 UIView
子类,并且 (b) 覆盖其 hitTest
实现以考虑表示层:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if ([self.layer.presentationLayer hitTest:[self convertPoint:point toView:self.superview]]) {
return self;
} else {
return nil;
}
}