TextKit框架详细解析 (十) —— 文本编程指南之复制、剪切和粘贴操作(六)

版本记录

版本号 时间
V1.0 2018.09.01

前言

TextKit框架是对Core Text的封装,用简洁的调用方式实现了大部分Core Text的功能。 TextKit是一个偏上层的开发框架,在iOS7以上可用,使用它可以方便灵活处理复杂的文本布局,满足开发中对文本布局的各种复杂需求。TextKit实际上是基于CoreText的一个上层框架,其是面向对象的。接下来几篇我们就一起看一下这个框架。感兴趣的看下面几篇文章。
1. TextKit框架详细解析 (一) —— 基本概览和应用场景(一)
2. TextKit框架详细解析 (二) —— 基本概览和应用场景(二)
3. TextKit框架详细解析 (三) —— 一个简单布局示例(一)
4. TextKit框架详细解析 (四) —— 一个简单布局示例(二)
5. TextKit框架详细解析 (五) —— 文本编程指南之简介(一)
6. TextKit框架详细解析 (六) —— 文本编程指南之展示文本内容(二)
7. TextKit框架详细解析 (七) —— 文本编程指南之排版概念(三)
8. TextKit框架详细解析 (八) —— 文本编程指南之管理Text Fields and Text Views(四)
9. TextKit框架详细解析 (九) —— 文本编程指南之管理键盘(五)

Copy, Cut, and Paste Operations - 复制、剪切和粘贴操作

用户可以在一个应用程序中复制文本,图像或其他数据,并将该数据粘贴到同一应用程序或不同应用程序中的其他位置。 例如,您可以在电子邮件中复制个人的地址,并将其粘贴到Contacts应用中的相应field中。 UIKit框架在UITextViewUITextField类中实现了copy-cut-paste。 如果您希望在自己的应用程序中使用此行为,则可以使用这些类的对象,也可以自行实现copy-cut-paste

以下部分描述了UIKit的编程接口,用于复制,剪切和粘贴操作,并说明如何使用它们。

注意:有关复制和粘贴操作的使用指南,请参阅iOS Human Interface Guidelines中的Supporting Copy and Paste


Copy-Paste Operations in UIKit - UIKit中的复制粘贴操作

UIKit框架的几个类和非正式协议为您提供了在应用程序中实现复制,剪切和粘贴操作所需的方法和机制:

  • UIPasteboard类提供粘贴板:用于在应用程序内或应用程序之间共享数据的保护区域。该类提供了在粘贴板上写入和读取数据项的方法。
  • UIMenuController类在选择的上方或下方显示要复制,剪切或粘贴的编辑菜单。编辑菜单的默认命令是(可能)复制,剪切,粘贴,选择和全选。您还可以将自定义菜单项添加到编辑菜单(请参阅 Adding Custom Items to the Edit Menu)。
  • UIResponder类声明方法canPerformAction:withSender:。响应者类可以实现此方法,以根据当前上下文显示和删除编辑菜单的命令。
  • UIResponderStandardEditActions非正式协议声明了用于处理复制,剪切,粘贴,选择和全选命令的接口。当用户点击编辑菜单中的一个命令时,将调用相应的UIResponderStandardEditActions方法。

Pasteboard Concepts - 粘贴板概念

粘贴板是用于在应用程序内或应用程序之间交换数据的标准化机制。粘贴板最常用的用途是处理复制,剪切和粘贴操作:

  • 当用户在应用程序中选择数据并选择“复制(或剪切)”菜单命令时,所选数据将被放置到粘贴板上。
  • 当用户选择“粘贴”菜单命令(在相同或不同的应用程序中)时,粘贴板上的数据将从粘贴板复制到当前应用程序。

在iOS中,粘贴板也用于支持查找操作。此外,您可以使用粘贴板使用自定义URL方案而不是复制,剪切和粘贴命令在应用之间传输数据;有关此技术的信息,请参阅Updating Your Info.plist

无论操作如何,使用粘贴板对象执行的基本任务都是将数据写入粘贴板并从粘贴板读取数据。虽然这些任务在概念上很简单,但它们掩盖了许多重要的细节。主要的复杂性是可能有多种方式来表示数据,这种复杂性导致了对效率的考虑。以下各节将讨论这些问题和其他问题。

1. Named Pasteboards

粘贴板可以是公共的或私人的。公共粘贴板称为系统粘贴板;私人粘贴板由应用程序创建,因此称为app粘贴板。粘贴板必须具有唯一的名称。 UIPasteboard定义了两个系统粘贴板,每个粘贴板都有自己的名称和用途:

  • UIPasteboardNameGeneral用于涉及各种数据类型的剪切,复制和粘贴操作。您可以通过调用generalPasteboard类方法获取表示常规粘贴板的单例对象。
  • UIPasteboardNameFind用于搜索操作。用户在搜索栏(UISearchBar)中当前键入的字符串将写入此粘贴板,因此可以在应用程序之间共享。您可以通过调用pasteboardWithName:create:类方法获取表示查找粘贴板的对象,并为该名称传入UIPasteboardNameFind

通常您使用系统定义的粘贴板之一,但如果需要,您可以使用pasteboardWithName:create:创建自己的应用粘贴板。如果您调用pasteboardWithUniqueNameUIPasteboard会为您提供一个具有唯一名称的应用粘贴板。您可以通过其name属性发现粘贴板的名称。

2. Pasteboard Persistence - 粘贴板持久性

粘贴板可以是持久的。 当粘贴板持久存在时,它将继续存在于应用程序终止之后并且跨系统重新启动。 系统粘贴板是持久的。 虽然默认情况下应用程序粘贴板不是持久性的,但应用程序可以通过将persistent属性设置为YES将它们标记为持久性。 不持久的应用程序粘贴板只会持续到拥有(创建)应用程序退出。 在卸载创建它的应用程序时,将删除持久性应用程序粘贴板。

3. Pasteboard Owner and Items - 粘贴板所有者和项目

最后将数据放到粘贴板上的对象称为粘贴板所有者。 放置在粘贴板上的每条数据都被视为粘贴板项目。 粘贴板可以容纳单个或多个项目。 应用可以根据需要放置或检索任意数量的项目。 例如,假设视图中的用户选择包含文本和图像。 通过粘贴板,您可以将文本和图像作为单独的项目复制到粘贴板。 从粘贴板读取多个项目的应用程序可以选择仅采用它支持的项目(例如文本,但不包括图像)。

重要提示:当应用程序将数据写入粘贴板时,即使它只是一个项目,该数据也会替换粘贴板的当前内容。 虽然您可以使用UIPasteboardaddItems:方法来追加项目,但是类的write方法不会将项目附加到粘贴板的当前内容。

4. Representations and UTIs

粘贴板操作通常在两个不同的应用程序之间执行。两个应用程序都不需要知道另一个应用程序,包括它可以处理的数据类型。为了最大化共享的可能性,粘贴板可以保存同一粘贴板项目的多个表示。例如,富文本编辑器可能提供复制数据的HTML,PDF和纯文本表示。粘贴板上的项目包括应用程序可以提供的该数据项的所有表示。

粘贴板项的每个表示通常由唯一类型标识符(Unique Type Identifier - UTI)标识。 (UTI只是一个唯一标识特定数据类型的字符串。)UTI提供了一种识别数据类型的通用方法。如果您希望支持自定义数据类型,则必须为其创建唯一标识符。为此,您可以对表示类型字符串使用反向DNS表示法以确保唯一性;例如,自定义表示类型可以是com.myCompany.myApp.myType。有关UTI的更多信息,请参阅Uniform Type Identifiers Overview

例如,假设某个应用程序支持选择富文本和图像。它可能希望在粘贴板上放置文本选择的富文本和Unicode版本以及图像选择的不同表示。每个项目的每个表示都存储有自己的数据,如图5-所示

Figure 5-1 Pasteboard items and representations

通常,为了最大化共享的可能性,粘贴板项目应包括尽可能多的不同表示。

粘贴板阅读器必须找到最适合其功能的数据类型(如果有)。 通常,这意味着选择最丰富的类型。 例如,文本编辑器可能提供HTML(富文本)和复制文本数据的纯文本表示。 支持富文本的应用程序应检索HTML表示,并且仅支持纯文本的应用程序应检索纯文本版本。

5. Change Count - 更改数量

更改计数是每个粘贴板变量,每次粘贴板的内容发生更改时都会增加 - 特别是在添加,修改或删除项目时。 通过检查更改计数(通过changeCount属性),应用程序可以确定粘贴板中的当前数据是否与上次接收的数据相同。 每次更改计数递增时,粘贴板都会向感兴趣的观察者发送通知。


First Steps: Identify the Selection and Display the Edit Menu - 第一步:确定选择并显示编辑菜单

如果要复制,剪切或粘贴某些内容,首先必须选择它。 (粘贴操作通常在空的选择上操作,例如插入符号,指示项目集合中的位置。)选择项目后 - 并在视觉上指示选择 - 您应该显示编辑菜单。 编辑菜单是一个系统菜单,可能包含以下命令:复制,剪切,粘贴,选择和全选。 编辑菜单指向选择。 当用户点击菜单项时,将调用相应的UIResponderStandardEditActions方法实现(例如cut:paste :)。

有关选择的更多信息以及如何显示和管理编辑菜单,请参阅Managing the Selection and the Edit Menu


Copying and Cutting the Selection - 复制和剪切选择

当用户点击编辑菜单的“复制”或“剪切”命令时,系统会调用实现它的响应器对象的copy:cut:方法。通常第一个响应者 - 您的自定义视图 - 实现这些方法,但如果第一个响应者没有实现它们,则消息以通常的方式沿响应者链向上传播。请注意,UIResponderStandardEditActions非正式协议声明了这些方法。

注意:由于UIResponderStandardEditActions是一种非正式协议,因此应用程序中的任何类都可以实现其方法。但是为了利用遍历响应者链的默认行为,实现这些方法的类应该从UIResponder继承,并且应该安装在响应者链中。

在响应copy:cut:消息时,您可以使用尽可能多的不同表示将选择所代表的对象或数据写入粘贴板。此操作涉及以下步骤(假设单个粘贴板项目):

  • 1)从选择中,识别或获得对象或对应于对象的二进制数据。二进制数据必须封装在NSData对象中。如果要将另一种类型的对象写入粘贴板,它必须是属性列表对象 - 即以下类之一的对象:NSString,NSArray,NSDictionary,NSDate,NSNumber或NSURL。 (有关属性列表对象的更多信息,请参阅Property List Programming Guide。)

  • 2)如果可能,生成对象或数据的一个或多个其他表示。例如,如果在上一步中创建了表示所选图像的UIImage对象,则可以使用UIImageJPEGRepresentationUIImagePNGRepresentation函数将图像转换为不同的表示形式。

  • 3)获取粘贴板对象。在许多情况下,这是一般的粘贴板,您可以通过generalPasteboard类方法获得。

  • 4)为写入粘贴板项目的每个数据表示分配一个合适的UTI。有关此主题的讨论,请参阅Pasteboard Concepts

  • 5)将数据写入每个表示类型的第一个粘贴板项:

  • 6)如果命令为Cut(cut:method),则从应用程序的数据模型中删除选择所代表的对象并更新视图。

Listing 5-1显示了copy:cut:方法的实现。 cut:方法调用copy:方法,然后从视图和数据模型中删除所选对象。请注意,copy:方法存档自定义对象以获取可以传递给setData:forPasteboardType:中的粘贴板的NSData对象。

// Listing 5-1  Copying and cutting operations

- (void)copy:(id)sender {
    UIPasteboard *gpBoard = [UIPasteboard generalPasteboard];
    ColorTile *theTile = [self colorTileForOrigin:currentSelection];
    if (theTile) {
        NSData *tileData = [NSKeyedArchiver archivedDataWithRootObject:theTile];
        if (tileData)
            [gpBoard setData:tileData forPasteboardType:ColorTileUTI];
    }
}
 
- (void)cut:(id)sender {
    [self copy:sender];
    ColorTile *theTile = [self colorTileForOrigin:currentSelection];
 
    if (theTile) {
        CGPoint tilePoint = theTile.tileOrigin;
        [tiles removeObject:theTile];
        CGRect tileRect = [self rectFromOrigin:tilePoint inset:TILE_INSET];
        [self setNeedsDisplayInRect:tileRect];
     }
}

Pasting the Selection - 粘贴选择

当用户点击编辑菜单的粘贴命令时,系统会调用实现它的响应器对象的paste:方法。通常第一个响应者 - 您的自定义视图 - 实现此方法,但如果第一个响应者没有实现它,则消息以通常的方式传递给响应者。 paste:方法由UIResponderStandardEditActions非正式协议声明。

在响应paste:消息时,您可以使用应用支持的表示形式从粘贴板中读取对象。然后将粘贴的对象添加到应用程序的数据模型,并在用户指示的位置的视图中显示新对象。此操作涉及以下步骤(假设单个粘贴板项目):

  • 1)获取粘贴板对象。在许多情况下,这是一般的粘贴板,您可以通过generalPasteboard类方法获得。

  • 2)通过调用containsPasteboardTypes:方法或pasteboardTypes方法,然后检查返回的类型数组,验证第一个粘贴板项目是否包含应用程序可以处理的表示形式的数据。请注意,您应该已经在canPerformAction:withSender:的实现中执行了此步骤。

  • 3)如果粘贴板的第一项包含应用程序可以处理的数据,请调用以下方法之一来读取它:

  • 4)将对象添加到应用程序的数据模型中。

  • 5)在用户指定的用户界面中显示对象的表示形式。

Listing 5-2paste:方法的一个实现示例。它与组合就剪切和复制方法相反。自定义视图首先查看常规粘贴板是否保存其自定义数据表示形式;如果是这样,它会从粘贴板读取数据,将其添加到应用程序的数据模型中,并标记自身的一部分 - 当前选择 - 用于重绘。

// Listing 5-2  Pasting data to a selection

- (void)paste:(id)sender {
    UIPasteboard *gpBoard = [UIPasteboard generalPasteboard];
    NSArray *pbType = [NSArray arrayWithObject:ColorTileUTI];
    ColorTile *theTile = [self colorTileForOrigin:currentSelection];
    if (theTile == nil && [gpBoard containsPasteboardTypes:pbType]) {
        NSData *tileData = [gpBoard dataForPasteboardType:ColorTileUTI];
        ColorTile *theTile = (ColorTile *)[NSKeyedUnarchiver unarchiveObjectWithData:tileData];
        if (theTile) {
            theTile.tileOrigin = self.currentSelection;
            [tiles addObject:theTile];
            CGRect tileRect = [self rectFromOrigin:currentSelection inset:TILE_INSET];
            [self setNeedsDisplayInRect:tileRect];
        }
    }
}

Ending an Operation - 结束操作

当您执行cut:,copy:paste:命令返回时,编辑菜单会自动隐藏。 如果需要,您可以以编程方式使其可见。 有关更多信息,请参阅Dismissing the Edit Menu

后记

本篇主要讲述了复制、剪切和粘贴操作,感兴趣的给个赞或者关注~~~

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

推荐阅读更多精彩内容