下面要为TouchTracker增加另一项功能:当用户选中某根线条时,TouchTracker要在用户手指按下的位置显示一个菜单。这个菜单要为用户提供一个删除选项。iOS SDK提供了一个名为UIMenuController的类,可以用来显示这类菜单。UIMenuController对象可以包含一组UIMenuItem对象(菜单项),并能在现有的视图上显示这些UIMenuItem对象。每个UIMenuItem对象都有自己的标题(会在菜单中显示)和动作方法(UIMenuItem对象会向第一响应对象发送动作消息)(见图13-3)。
图13-3 UIMenuController对象示例
每个iOS应用只有一个UIMenuController对象。当应用要显示该对象时,要先为它设置一组UIMenuItem对象,然后设置显示位置(矩形区域),最后将其设置为可见。在BNRDrawView.m的tap:中完成上述过程,使TouchTracker能够在用户按下线条时,在按下的位置显示菜单。此外,还要在tap:中实现隐藏菜单的功能:当手指按下的位置附近没有线条时,TouchTracker要取消当前选中的线条并隐藏UIMenuController对象,代码如下:
- (void)tap:(UIGestureRecognizer *)gr
{
NSLog(@“Recognized tap”);
CGPoint point = [gr locationInView:self];
self.selectedLine = [self lineAtPoint:point];
if (self.selectedLine) {
// 使视图成为UIMenuItem动作消息的目标
[self becomeFirstResponder];
// 获取UIMenuController对象
UIMenuController *menu = [UIMenuController sharedMenuController];
// 创建一个新的标题为“Delete”的UIMenuItem对象
UIMenuItem *deleteItem = [[UIMenuItem alloc]
initWithTitle:@“Delete” action:@selector(deleteLine:)];
menu.menuItems = @[deleteItem];
// 先为UIMenuController对象设置显示区域,然后将其设置为可见
[menu setTargetRect:CGRectMake(point.x, point.y, 2, 2) inView:self];
[menu setMenuVisible:YES animated:YES];
} else {
// 如果没有选中的线条,就隐藏UIMenuController对象
[[UIMenuController sharedMenuController] setMenuVisible:NO
animated:YES];
}
[self setNeedsDisplay];
}
要显示UIMenuController对象,还要满足一个条件:显示UIMenuController对象的UIView对象必须是当前UIWindow对象的第一响应对象。这也是为什么在tap:的起始部分会向BNRDrawView对象发送becomeFirstResponder消息。如果要将某个自定义的UIView子类对象设置为第一响应对象,就必须覆盖该对象的canBecomeFirstResponder方法。
在BNRDrawView.m中覆盖canBecomeFirstResponder方法并返回YES,代码如下:
- (BOOL)canBecomeFirstResponder
{
return YES;
}
构建并运行应用,选中某根线条,但是TouchTracker并不会按预期显示UIMenuController对象。这是因为该对象在显示前会枚举所有的UIMenuItem对象,检查第一响应对象是否实现了指定的动作方法。如果没有实现该方法,UIMenuController对象就不会显示相应的UIMenuItem对象;如果所有UIMenuItem对象的动作方法都没有实现,应用就不会显示UIMenuController对象。
在BNRDrawView.m中实现deleteLine:,显示UIMenuController对象和Delete菜单项,代码如下:
- (void)deleteLine:(id)sender
{
// 从已经完成的线条中删除选中的线条
[self.finishedLines removeObject:self.selectedLine];
// 重画整个视图
[self setNeedsDisplay];
}
构建并运行应用。画一根线条,按下并选中该线条,选择菜单中的Delete菜单项,TouchTracker应该会删除这根线条。