显示和管理编辑菜单
编辑菜单是一个上下文菜单,显示该菜单是为了提供可在选定内容(如Text view中的单词或图像)上执行的命令。edit菜单是copy、cut和paste操作的组成部分,它(潜在地)显示了copy、cut、paste、Select和Select All命令。但是,您可以将自定义菜单项添加到编辑菜单,以对选择执行其他类型的操作。
要在视图中复制或剪切某个内容,或者对其进行任何其他操作,都必须选中该“某物”。它可以是文本、图像、URL、颜色或任何其他数据表示形式(包括自定义对象)。您必须自己管理该视图中对象的选择。如果用户通过某种触摸手势(例如双击)在视图中选择了一个对象,则必须处理该事件,在内部记录选择(并取消选择之前的任何选择),并可能在视图中显示新的选择。如果用户可以在你的视图中选择多个对象进行复制-剪切-粘贴操作,你必须实现这种多重选择行为。
注意:处理触摸事件的技术,包括手势识别器的使用,将在Event Handling Guide for iOS中讨论。
当你的应用程序确定用户请求了编辑菜单(可能是进行选择的操作)时,你应该完成以下步骤来显示菜单:
- 调用UIMenuController的sharedMenuController类方法来获取全局菜单控制器实例。
- 计算选区的边界,对得到的矩形调用setTargetRect:inView:方法。编辑菜单显示在这个矩形的上方或下方,取决于所选内容离屏幕的顶部或底部有多近。
- 调用setMenuVisible:animated:方法(两个参数都是YES),以动画的方式显示编辑菜单在选定区域的上方或下方。 清单7-1展示了如何在touchesEnded:withEvent:方法的实现中显示edit菜单,该方法用于处理复制、剪切和粘贴操作。(注意,示例中省略了处理选择的代码部分。)这段代码还显示了自定义视图向自己发送一个becomeFirstResponder消息,以确保它是后续复制、剪切和粘贴操作的第一个响应程序。
Listing 7-1 Displaying the edit menu
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *theTouch = [touches anyObject];
if ([theTouch tapCount] == 2 && [self becomeFirstResponder]) {
// selection management code goes here...
// bring up edit menu.
UIMenuController *theMenu = [UIMenuController sharedMenuController];
CGRect selectionRect = CGRectMake (currentSelection.x, currentSelection.y, SIDE, SIDE);
[theMenu setTargetRect:selectionRect inView:self];
[theMenu setMenuVisible:YES animated:YES];
}
}
菜单最初包括第一个响响者有相应uiresponderstandardditactions方法实现的所有命令(copy:、paste:等)。然而,在菜单显示之前,系统发送canPerformAction:withSender:消息给第一个响应程序,在许多情况下是自定义视图本身。在这个方法的实现中,响应者会评估命令(由第一个参数中的选择器表示)是否适用于当前上下文中。例如,如果选择器是paste:并且剪贴板中没有视图可以处理的类型的数据,则响应器应该返回no以抑制paste命令。如果第一个响响者没有实现canPerformAction:withSender:方法,或者没有处理给定的命令,消息会沿着响响者链向上传播。
清单7-2展示了canPerformAction:withSender:方法的一个实现,该方法查找匹配cut:、copy:和paste:选择器的消息;它基于当前选择上下文启用或禁用复制、剪切和粘贴菜单命令,对于粘贴,则启用或禁用剪贴板的内容。
Listing 7-2 Conditionally enabling menu commands
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
BOOL retValue = NO;
ColorTile *theTile = [self colorTileForOrigin:currentSelection];
if (action == @selector(paste:) )
retValue = (theTile == nil) &&
[[UIPasteboard generalPasteboard] containsPasteboardTypes:
[NSArray arrayWithObject:ColorTileUTI]];
else if ( action == @selector(cut:) || action == @selector(copy:) )
retValue = (theTile != nil);
else
retValue = [super canPerformAction:action withSender:sender];
return retValue;
}
注意,这个方法的最后一个else子句调用了超类的实现,让任何超类有机会处理子类选择忽略的命令。
注意,当执行菜单命令时,可以更改其他菜单命令的上下文。例如,如果用户选择视图中的所有对象,则菜单中应该包含复制和剪切命令。在这种情况下,响应程序可以在菜单仍然可见的情况下,调用菜单控制器上的update;这导致在第一响应者上重新调用canPerformAction:withSender:。
向“编辑”菜单中添加自定义项
您可以将自定义项添加到“编辑”菜单。当用户点击此选项时,将发出一个命令,以特定于应用程序的方式影响当前目标。UIKit框架通过target-action机制来实现这一点。图7-1展示了一个自定义菜单项(" Change Color ")。
Figure 7-1 An edit menu with a custom menu item
UIMenuItem类的一个实例表示一个自定义菜单项。UIMenuItem对象有两个属性,一个title和一个action选择器,你可以随时修改它们。要实现一个自定义菜单项,你必须用这些属性初始化一个UIMenuItem实例,将实例添加到菜单控制器的自定义菜单项数组中,然后在相应的responder子类中实现处理命令的action方法。
实现自定义菜单项的其他方面对于使用单例UIMenuController对象的所有代码都是通用的。在一个自定义或覆盖的视图中,你将视图设置为第一个响应程序,获取共享菜单控制器,设置一个目标矩形,然后通过调用setMenuVisible:animated:来显示编辑菜单。清单7-3中的简单示例添加了一个自定义菜单项,用于在红色和黑色之间更改自定义视图的颜色。
Listing 7-3 Implementing a Change Color menu item
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *theTouch = [touches anyObject];
if ([theTouch tapCount] == 2) {
[self becomeFirstResponder];
UIMenuItem *menuItem = [[UIMenuItem alloc] initWithTitle:@"Change Color" action:@selector(changeColor:)];
UIMenuController *menuCont = [UIMenuController sharedMenuController];
[menuCont setTargetRect:self.frame inView:self.superview];
menuCont.arrowDirection = UIMenuControllerArrowLeft;
menuCont.menuItems = [NSArray arrayWithObject:menuItem];
[menuCont setMenuVisible:YES animated:YES];
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {}
- (BOOL)canBecomeFirstResponder { return YES; }
- (void)changeColor:(id)sender {
if ([self.viewColor isEqual:[UIColor blackColor]]) {
self.viewColor = [UIColor redColor];
} else {
self.viewColor = [UIColor blackColor];
}
[self setNeedsDisplay];
}
关闭编辑菜单
当系统或自定义命令的实现返回时,编辑菜单将自动隐藏。你可以使用下面的代码保持菜单的可见性:
[UIMenuController sharedMenuController].menuVisible = YES;
系统可以随时隐藏编辑菜单。例如,当显示警告框或用户点击屏幕的其他区域时,它会隐藏菜单。如果您有依赖于edit菜单是否可见的状态或显示,则应该侦听名为UIMenuControllerWillHideMenuNotification的通知并采取适当的操作。