iOS文本编程指南(八)

展示并操作编辑菜单

编辑菜单是一个上下文菜单,它展示并提供了一些命令,这些命令能够操作选中内容,例如一个文本页面中的文字或者图片。编辑菜单是复制,剪切,粘贴操作的一个组成部分。它默认展示复制,剪切,粘贴,选中以及全选的命令。然后,你可以添加一个自定义的条目到编辑菜单来对选中内容进行其他操作。

管理选中和编辑菜单

为了在一个页面中复制或剪切一些东西,这些东西必须是被选中的。可以是一串文本,一张图片,一个URL,一个颜色,或者是其他种类的数据,包括自定义对象。你必须自己管理页面中选中的对象。如果用户通过使用某种手势选择了页面中的对象,你必须要处理这个事件,记录选中区域(取消选中之前已选中内容),并在页面上标记出选中的内容。可以允许用户选中多个对象,执行复制,剪切,粘贴操作,你必须自己实现这种多选行为。

注:对于处理触摸事件,包括手势的内容,查看Event Handling Guide for iOS

当你的应用识别出用户已经请求了编辑菜单——也就是产生了一次选中行为——你应该完成以下几步来展示菜单:

  1. 调用UIMenuController的sharedMenuController类方法获取全局的实例。
  2. 计算选中区域的边界,并将结果传给setTargetRect:inView:方法。编辑菜单将在这个区域的上面或者下面出现(取决于选中区域距离屏幕顶部及底部的距离)。
  3. 调用setMenuVisible:animated方法让编辑菜单显示出来。

下面代码展示了你应该如何在touchesEnded:withEvent:方法中展示编辑菜单,用以处理复制,剪切,粘贴操作。(注意,示例代码省略了处理选中的代码。)代码也展示了自定义页面发送becameFirstResponder消息来确保成为接下来复制,剪切,粘贴操作的第一响应者。

- (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];

    }
}

菜单初始包括所有第一响应者实现了UIResponderStandardEditActions方法的行为(copy: paste:等)。在菜单出现之前,系统发送canPerformAction:withSender:消息到第一响应者。在该方法的实现中,响应者评估该命令(第一个参数selector中传递)是否适用于当前场合。例如,如果selector是paste:并且剪切板中没有该页面能够处理的数据,响应者应当返回NO,来取消粘贴命令的展示。如果第一响应者没有实现canPerformAction:withSender:方法,或者没有处理指定命令,消息将沿响应链传递下去。

下面代码展示了canPerform:withSender方法的实现,查找并匹配了cut:,copy:以及paste:方法。基于当前的选中文本以及剪切板内容,会开启或关闭复制,剪切,粘贴等菜单命令。

- (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里调用了父类的实现,父类就有机会处理子类选择忽略的命令。

注意菜单命令在执行后,可能会改变其他菜单命令。例如,当用户执行了全选操作,复制和剪切操作应当出现在菜单中。在这种情况下,响应者可以在菜单始终可见的情况下通过调用menu controller的update方法更新菜单,这就导致了canPerformAcation:withSender:的调用。

添加自定义条目至编辑菜单

你可以添加自定义条目到编辑菜单。当用户点击此项时,将发出一个命令,该命令将以特定应用程序的方式影响当前目标。UIKit通过target-action机制完成该目的。该条目的点击导致了一个行为消息被发送到响应链中第一个能处理该消息的对象。下图展现了一个自定义条目的例子

UIMenuItem的实例代表自定义条目。UIMenuItem对象有两个属性,title和action selector,都可以任意时刻修改。要实现一个自定义菜单条目,你必须初始化这个UIMenuItem实例的这些属性,将该实例添加到menu controller的自定义菜单条目数组中,并在合适的响应者类中实现该命令的操作。

其他方面是各处通用的:使用UIMenuController的单例对象。在自定义或者重写的页面中,你设置了页面为第一响应者,获取menu controller单例,设置一个目标rectangle,通过调用setMenuVisible:animated:方法展示编辑菜单。下面代码是一个添加自定义菜单项的简单例子。

- (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];
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容