我有一个长按手势识别器的视图:
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressDetected:)];
[self addGestureRecognizer:longPress];
[longPress release];
}
return self;
}
当检测到长按时,我想在视图上方显示一个UIMenuViewController,其中包含一个动作,当点击该菜单项时,我想执行一个块:
- (void)longPressDetected:(UILongPressGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateBegan) {
[self becomeFirstResponder];
UIMenuController *menuController = [UIMenuController sharedMenuController];
UIMenuItem *actionItem = [[UIMenuItem alloc] initWithTitle:@"Action" action:@selector(someActionSelector)];
[menuController setMenuItems:[NSArray arrayWithObject:actionItem]];
[actionItem release];
[menuController setTargetRect:self.frame inView:self.superview];
[menuController setMenuVisible:YES animated:YES];
}
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
if (action == @selector(copy:) || action == @selector(cut:) || action == @selector(delete:) ||
action == @selector(paste:) || action == @selector(select:) || action == @selector(selectAll:)) {
return NO;
}
else if (action == @selector(someActionSelector)) {
return YES;
}
else {
return [super canPerformAction:action withSender:sender];
}
}
- (void)someActionSelector {
if (self.actionBlock) {
self.actionBlock();
}
}
问题是,这仅在第二次长按并点击组合后才有效。我第一次长按视图时看到菜单,但点击菜单什么也没做。第二次再次看到菜单时,我点击它,然后执行该块。
调试器显示someActionSelector
中的断点仅在第二次点击时到达。知道为什么会这样吗?
答案 0 :(得分:0)
我明白了。监听长按的视图包含在一个视图中,该视图在其帧被更改时重新定位一些子视图(通过覆盖setFrame:
,这似乎是一个坏主意,但我想不出另一种方式)。因此,当长按发生时,它在侦听视图的父节点的父节点中触发layoutSubviews
,其设置侦听视图的父节点的帧,其重新定位侦听视图,这看起来打破了响应者链接或停用菜单。解决方案是在被覆盖的setFrame:
内添加一个条件,以便仅在框架实际更改时触发布局,而不是长按。我确信有一个更好的选择,可以完全避免这个问题的框架更改 - 随意在评论中提出建议。