复制、剪切、和粘贴操作(一) <- iOS文本编程指南
用户可以在一个app中复制文本、图片、或者其他数据,并粘贴该数据到该app的其他位置,或不同的app中。例如,你可以在email信息中复制一个人的地址,并把它粘贴到“联系人”app的合适字段中。UIKit框架在UITextView和UITextField类中实现了复制-剪切-粘贴。如果你想在自己的app中使用该功能,你可以使用这些类的对象,也可以实现自己复制-剪切-粘贴。
接下来的部分将描述使用复制、剪切、和粘贴操作的UIKit编程接口,并解释它们是如何做到的。
注意:对于复制和粘贴操作相关的指南,参见iOS Human Interface Guidelines中的“Supporting Copy and Paste”。
UIKit中的复制-粘贴操作
UIKit框架中的多个类和一个非正式协议,给了你在app中实现复制、剪切、和粘贴所需方法和机制:
- UIPasteboard类提供剪贴板:在app中或app之间共享数据的保护区域。该类提供方法,可以从剪贴板读取数据的项目,也可以向粘贴半写入数据的项目。
- UIMenuController类在选中部分的上面或者下面显示一个编辑按钮,用以复制、剪切、或者粘贴。默认的编辑菜单命令是(可能是)复制、剪切、粘贴、选择、及选择全部。你还可以添加自定义菜单项目到编辑菜单(参见Adding Custom Items to the Edit Menu)。
- UIResponder类声明了canPerformAction:withSender:方法。Responder类可以实现该方法来显示和移除基于当前内容的编辑菜单的命令。
- UIResponderStandardEditActions非正式协议声明了处理复制、剪切、粘贴、选择、以及选择全部命令的接口。当用户点击在编辑菜单中点击其中一个命令时,对应的UIResponderStandardEditActions方法会被调用。
剪贴板概念
剪贴板是在app内或app间交换数据的标准化机制。剪贴板最常用于处理复制、剪切、以及粘贴操作:
- 当用户选择app中的数据并选择复制(或剪切)命令时,该被选中的数据会被放置到剪贴板上。
- 当用户选择粘贴命令时(可以在相同或者不同的app中),剪贴板上的数据被复制到当前的app中。
在iOS中,剪贴板也用于支持查找操作。此外,您可以使用剪贴板在应用程序之间使用自定义URL方案传输数据,而不是复制,剪切和粘贴命令;有关此技术的信息,参见Updating Your Info.plist Settings。
无论操作如何,使用剪贴板对象的基本任务就是向其写入数据以及从其中读取数据。尽管这些任务概念上很简单,但是它们掩盖了一些重要的细节。主要的复杂性是可以有多中方法表示数据,而这种复杂性带来了效率问题。这些以及其他问题在下面部分讨论。
命名剪贴板
剪贴板可以是公共的也可以是私有的。公共的剪贴板被称为系统剪贴板;私有的剪贴板是由app创建的,于是被称为app剪贴板。剪贴板必须有唯一的名字。UIPasteboard定义了两个系统剪贴板,它们都有自己的名字和目的:
- UIPasteboardNameGeneral用于涉及广泛数据类型的剪切、复制、以及粘贴操作。你可以通过涉及的generalPasteboard类方法来获取表示通用剪贴板的单例对象。
- UIPasteboardNameFind是用于查找操作。当前用户在搜索栏中输入的字符串是写入到剪贴板,因此可以在不同app中共享。你可以通过调用pasteboardWithName:create:方法来获取到表示剪贴板的对象,传入UIPasteboardNameFind作为名字。
通常你使用一种系统定义的剪贴板,但是如有必要,你可以使用pasteboardWithName:create: 来创建你自己app的剪贴板。如果你嗲用了pasteboardWithUniqueName,UIPasteboard给你一个唯一名字的app剪贴板。你可以通过name属性发现剪贴板的名字。
剪贴板持久化
剪贴板可以被持久化。当剪贴板是持久化的时候,它可以在系统重启之后继续存在与之前的app中。系统剪贴板是持久化的。尽管app的剪贴板默认是不持久化的,但是app可以通过把持久化属性设置为YES来标记它的持久化功能。App剪贴板不会持久化,知道创建它或拥有它的app退出。持久化的app剪贴板在该app卸载的时候被移除。
剪贴板的所有者和项目
最后将数据放入剪贴板的对象被称为剪贴板的所有者。被放入剪贴板的数据的每个部分被称为剪贴板的项目。剪贴板可以有一个或者多个项目。App可以根据需要替换或者检索多个项目。例如,用户在一个包含文本和图片的视图中进行选择。剪贴板让你把复制的文本和图片分别作为项目。从剪贴板读取多个项目的app,可以选择只使用它支持的项目(例如,只有文本,而没有图片)。
重要:当app把数据写入剪贴板的时候,即使只有单个项目,该数据也会替换剪贴板中原油的内容。即使你使用UIPasteboard的addItems:方法来添加项目,类的写入方法也不会在剪贴板的当前内容后增加项目。
表示法和UTI
剪贴板操作经常被用到不同的app之间。应用之间无需知道彼此,包括它能处理的数据种类。为了最大化发挥共享的作用,一个剪贴板可以持有同一个剪贴板项目的多个表示法。例如,一个富文本编辑器或许提供了复制数据的HTML、PDF、以及纯文本表示法。剪贴板的一个项目包括了所有app可以提供的数据项目的表示法。
每个剪贴板项目的表示法通常通过唯一类型标识符(Unique Type Identifier,UTI)标识。(UTI是简单的字符串,它是一个特定数据类型的唯一标记。)UTI提供标记数据类型的通用方法。如果你有想要支持的自定义的数据类型,你必须为它创建唯一的标识符。为此,你可以使用反向DNS(reverse-DNS)符号表示类型字符串来确保唯一性;例如,一个自定义百澳是类型可以是com.myCompany.myApp.myType。更多UTI的信息,参见Uniform Type Identifiers Overview。
例如,假设一个app支持富文本和图片的选择。它或许想把富文本和所选文本的Unicode版本,以及所选图片的不同表示法放置到剪贴板。每个项目的每个表示法都存储有它们自己的数据,如图5-1所示。
图 5-1 剪贴板项目和表示法
通常情况下,为了最大化发挥共享的作用,剪贴板项目应该包含尽可能多的不同的表示法。
剪贴板读取器必须找到最合适它功能的数据类型(如果有的话)。通常,这意味着选择最丰富的可用类型。例如,一个文本编辑器或许提供了复制的数据的HTML(富文本)和纯文本表示法。支持副文本的app应该检索HTML表示法,而支持纯文本的app应该检索纯文本版本。
改变计数
改变计数是每个剪贴板都有的变量,每次剪贴板特定改变内容(当项目增加、修改、或者移动时)时它都会增加。通过检查改变计数(通过changeCount属性),app可以确定剪贴板中的当前数据和它最后接受的数据是否相同。每次改变计数都会增加,剪贴板会发送一个通知给感兴趣的观察者。
第一步:识别选择并显示编辑菜单
如果你打算复制、剪切、或粘贴什么的话,你首先必须选中它。(粘贴操作通常在一个空的位置操作,例如插入符,指示项目集合中的位置。)在选中了项目并可视化的指示了所选后,你应该显示编辑菜单。编辑菜单是系统菜单,它可能有如下命令:复制、剪切、粘贴、选择、和选择全部。编辑菜单在选中的位置。当用户点击菜单项时,响应的
UIResponderStandardEditActions方法实现(例如 cut:或 paster:)会被调用。
更多关于选择和如何显示和管理编辑菜单的内容,参见 Managing the Selection and the Edit Menu。