Text Programming Guide for iOS - 08 - Displaying and Managing the Edit Menu

196 阅读6分钟

显示和管理编辑菜单

编辑菜单是一个上下文菜单,显示该菜单是为了提供可在选定内容(如Text view中的单词或图像)上执行的命令。edit菜单是copy、cut和paste操作的组成部分,它(潜在地)显示了copy、cut、paste、Select和Select All命令。但是,您可以将自定义菜单项添加到编辑菜单,以对选择执行其他类型的操作。

要在视图中复制或剪切某个内容,或者对其进行任何其他操作,都必须选中该“某物”。它可以是文本、图像、URL、颜色或任何其他数据表示形式(包括自定义对象)。您必须自己管理该视图中对象的选择。如果用户通过某种触摸手势(例如双击)在视图中选择了一个对象,则必须处理该事件,在内部记录选择(并取消选择之前的任何选择),并可能在视图中显示新的选择。如果用户可以在你的视图中选择多个对象进行复制-剪切-粘贴操作,你必须实现这种多重选择行为。

注意:处理触摸事件的技术,包括手势识别器的使用,将在Event Handling Guide for iOS中讨论。

当你的应用程序确定用户请求了编辑菜单(可能是进行选择的操作)时,你应该完成以下步骤来显示菜单:

  1. 调用UIMenuController的sharedMenuController类方法来获取全局菜单控制器实例。
  2. 计算选区的边界,对得到的矩形调用setTargetRect:inView:方法。编辑菜单显示在这个矩形的上方或下方,取决于所选内容离屏幕的顶部或底部有多近。
  3. 调用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的通知并采取适当的操作。