復(fù)制撼港,剪切,粘貼操作
用戶可以復(fù)制某個(gè)應(yīng)用中的文本营曼,圖片,或者其他數(shù)據(jù)到另外一個(gè)地方愚隧,到該應(yīng)用內(nèi)或者另一個(gè)應(yīng)用都可以蒂阱。UIKit Framework在UITextView中實(shí)現(xiàn)了復(fù)制-剪切-粘貼操作,如果你想要擁有這些行為奸攻,你可以使用這些類或者自己實(shí)現(xiàn)復(fù)制-剪切-粘貼蒜危。
下面的內(nèi)容描述了UIKit的接口虱痕,如何使用復(fù)制睹耐,剪切,粘貼操作部翘。
注:和復(fù)制粘貼操作相關(guān)的指導(dǎo)硝训,看iOS Human Interface Guidelines.中的“Supporting Copy and Paste”一節(jié)
UIKit的復(fù)制粘貼操作
UIKit中提供了幾個(gè)類和一個(gè)非正式協(xié)議(譯者注:非正式協(xié)議在較早的版本用分類實(shí)現(xiàn),目前用協(xié)議實(shí)現(xiàn),協(xié)議中的方法為可選類型)以及一種機(jī)制窖梁,讓你能夠?qū)崿F(xiàn)復(fù)制赘风,剪切,粘貼操作纵刘。
- UIPasteboard類提供了剪切板:共享數(shù)據(jù)的保存的地方邀窃。這個(gè)類提供了從剪切板按條讀寫數(shù)據(jù)的方法。
- UIMenuController類展示了編輯菜單假哎,出現(xiàn)在選中內(nèi)容的上方或者下方瞬捕。編輯菜單默認(rèn)的命令是復(fù)制,剪切舵抹,粘貼肪虎,選中和全選。你可以在編輯菜單中添加自定義條目惧蛹。
- UIResponder類聲明了canPerformAction:withSender:方法扇救。響應(yīng)類可以實(shí)現(xiàn)該方法,來讓某些編輯條目根據(jù)當(dāng)前選中內(nèi)容出現(xiàn)或移除香嗓。
- UIResponderStandardEditActions 非正式協(xié)議聲明了處理復(fù)制迅腔,剪切,粘貼靠娱,選中以及全選命令的接口钾挟。當(dāng)用戶點(diǎn)擊了一個(gè)命令時(shí),響應(yīng)的方法會被調(diào)用饱岸。(譯者注:UITextView實(shí)現(xiàn)了改協(xié)議)
剪切板
剪切版是應(yīng)用內(nèi)或應(yīng)用間交換數(shù)據(jù)的的標(biāo)準(zhǔn)機(jī)制掺出。其最常見的用處是復(fù)制,剪切苫费,粘貼操作汤锨。
- 當(dāng)用戶選中了數(shù)據(jù),并且選擇了復(fù)制(或剪切)命令百框,那么被選中的數(shù)據(jù)就被放入了剪切板
- 當(dāng)用戶選擇了粘貼命令闲礼,在剪切板中的數(shù)據(jù)就被復(fù)制到了當(dāng)前應(yīng)用中。
在iOS中铐维,剪切板也用來支持查找操作柬泽。并且,你可以使用自定義的URL機(jī)制代替復(fù)制嫁蛇,剪切锨并,粘貼操作,讓剪切板在應(yīng)用間傳輸數(shù)據(jù)睬棚。具體信息參照Info.plist的設(shè)置第煮。
拋開具體操作解幼,剪切板的基本功能是往里寫數(shù)據(jù)和從中讀數(shù)據(jù)。雖然概念簡單包警,但是包含了諸多細(xì)節(jié)撵摆。主要復(fù)雜的地方在于數(shù)據(jù)的表達(dá)有多種方式,這種復(fù)雜性就導(dǎo)致了也需要考慮性能害晦。下面就會討論一下這些問題特铝。
命名剪切板
剪切板可能是共有的或是私有的。共有的剪切板被稱作系統(tǒng)剪切板壹瘟,私有的剪切板是應(yīng)用創(chuàng)建的苟呐,因此被稱作應(yīng)用剪切板。剪切板必須擁有一個(gè)唯一的名字俐筋。UIPasteboard定義了兩個(gè)系統(tǒng)剪切板牵素,它們的名字和用處如下:
- UIPasteboardNameGeneral 涉及多種類型數(shù)據(jù)的剪切,復(fù)制和粘貼操作澄者。你可以通過generalPasteboard 類方法獲取這個(gè)單例笆呆。
- UIPasteboardNameFind 用作查找操作。用戶在UISearchBar中輸入的字符串會被寫入到該剪切板中粱挡,因此可以在應(yīng)用間共享赠幕。你可以通過調(diào)用 pasteboardWithName:create:類方法,傳入U(xiǎn)IPasteboardNameFind參數(shù)來獲取該對象询筏。
通常你都會使用系統(tǒng)剪切板榕堰,如果有必要你可以通過調(diào)用cpasteboardWithName:create:方法創(chuàng)建你自己的應(yīng)用剪切板。調(diào)用pasteboardWithUniqueName這個(gè)方法也可以嫌套,一個(gè)擁有唯一名字的應(yīng)用剪切板會被創(chuàng)建出來逆屡,名字可以通過剪切板對象的name屬性查看。
剪切板的持久化
剪切板能夠被持久化踱讨。如果剪切板被持久化魏蔗,可以在之前的應(yīng)用退出之后或者系統(tǒng)重啟之后使用。系統(tǒng)剪切板是持久化的痹筛。雖然應(yīng)用剪切板默認(rèn)是不持久化的莺治,你可以通過設(shè)置persistent屬性為YES來使他們變成可持久化的。不持久化的剪切板在應(yīng)用退出時(shí)就沒了帚稠,持久化的剪切板在應(yīng)用卸載時(shí)被移除掉谣旁。
剪切板持有者和條目
最后一次向剪切板中加入數(shù)據(jù)的對象被視作剪切板持有者。每一條向剪切板中加入的數(shù)據(jù)被視作剪切板條目滋早。剪切板可以持有一條或多條條目榄审。應(yīng)用能夠加入和跟蹤任意數(shù)量的條目。例如馆衔,比如一個(gè)用戶選擇了文字+圖片瘟判。他們被復(fù)制到剪切板時(shí)怨绣,文本和圖片作為不同的條目角溃。應(yīng)用讀取多個(gè)條目拷获,可以選擇那些需要支持的(例如,只需要處理文字而不需要處理圖片)减细。
表示與UTI
剪切板操作經(jīng)常是跨應(yīng)用的匆瓜。沒有應(yīng)用可以知道另外一個(gè)應(yīng)用可以處理哪些數(shù)據(jù)。為了最大化這種共享的能力未蝌,剪切板可以對一個(gè)剪切板條目進(jìn)行多種表示驮吱。例如,一個(gè)富文本編輯器可能對一份拷貝數(shù)據(jù)提供了HTML萧吠,PDF和純文本的表示左冬。一個(gè)剪切板條目包括了應(yīng)用所能提供的所有表示。
每一個(gè)剪切板條目通常使用唯一類型標(biāo)識(UTI)纸型。(UTI就是一個(gè)唯一的字符串拇砰,用來標(biāo)記數(shù)據(jù)類型。)UTI提供了一個(gè)統(tǒng)一的標(biāo)記數(shù)據(jù)類型的方式狰腌。如果你有一個(gè)自定義的數(shù)據(jù)類型想要支持除破,你必須為它創(chuàng)建一個(gè)唯一的標(biāo)識。對此琼腔,你可以使用逆向域名來確保唯一性瑰枫,例如,一個(gè)自定義的類型表示可以是com.myCompany.myApp.myType丹莲。更多有關(guān)UTI的內(nèi)容光坝,查看Uniform Type Identifiers Overview。
舉個(gè)例子甥材,假設(shè)一個(gè)應(yīng)用支持富文本和圖片的選中教馆。它可能想將富文本的Unicode版本和圖片的多種表示都放到剪切板中。每一個(gè)條目的每種表示被存儲在它自身的數(shù)據(jù)中擂达,如下圖:
![](https://developer.apple.com/library/content/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/Art/items_representation_2x.png)
通常土铺,為了最大化能夠共享數(shù)據(jù)的可能性,剪切板條目應(yīng)當(dāng)包含盡可能多的表示板鬓。
一個(gè)剪切板的讀者必須找到最合適的數(shù)據(jù)類型悲敷。典型地,這意味著選擇能夠支持的最復(fù)雜類型俭令。例如后德,對于一份拷貝的文本數(shù)據(jù),文本編輯器應(yīng)該提供HTML和普通文本的表示抄腔。一個(gè)能夠支持富文本的應(yīng)用應(yīng)該使用HTML的表示瓢湃,而僅能支持普通文本的應(yīng)用就使用普通文本的版本理张。
改變數(shù)
改變數(shù)是剪切板的變量,每次當(dāng)剪切板的內(nèi)容發(fā)生變化時(shí)绵患,它就增加雾叭。具體指的是剪切板條目加入、修改或者刪除時(shí)落蝙。通過檢查改變數(shù)织狐,應(yīng)用能夠檢查當(dāng)前剪切板中的數(shù)據(jù)是否跟上次獲取到的一致。每次改變數(shù)增加時(shí)筏勒,剪切板會給觀察者發(fā)送通知移迫。
第一步:識別選中并展示編輯菜單
如果你想使用復(fù)制,剪切或者粘貼之類的東西管行,你首先需要選中(一個(gè)粘貼操作通常在一個(gè)空選中上操作厨埋,例如一個(gè)光標(biāo))。在選中一個(gè)條目之后捐顷,你應(yīng)該展示展示編輯菜單荡陷。編輯菜單是一個(gè)系統(tǒng)菜單,它可能包含以下命令:拷貝套菜,剪切亲善,粘貼,選中和全選逗柴。編輯菜單指向被選中內(nèi)容蛹头。當(dāng)用戶點(diǎn)擊一個(gè)菜單項(xiàng)時(shí),協(xié)議UIResponderStandardEditActions中的方法(諸如cut: paste:等方法)就會被調(diào)用戏溺。
獲取更多有關(guān)選中以及菜單的展示管理的內(nèi)容渣蜗,查看Managing the Selection and the Edit Menu
復(fù)制和剪切
當(dāng)用戶點(diǎn)擊復(fù)制后者剪切命令式,系統(tǒng)會調(diào)用相應(yīng)對象的copy:或者cut:方法旷祸。通常是第一響應(yīng)者實(shí)現(xiàn)了這些方法耕拷,如果第一響應(yīng)者沒有實(shí)現(xiàn)這些方法,消息會沿著響應(yīng)鏈傳遞托享。非正式協(xié)議UIResponderStandardEditActions中定義了這些方法骚烧。
注意:任何類可實(shí)現(xiàn)UIResponderStandardEditActions中的方法,但是最好是繼承UIResponder闰围,并在響應(yīng)鏈中的類赃绊。
實(shí)現(xiàn)copy:或者cut:方法時(shí),你應(yīng)該向剪切板中寫入選中數(shù)據(jù)的盡可能多的表達(dá)羡榴。這些操作包括以下步驟(假設(shè)只有一個(gè)剪切板條目):
從選中對象中獲取數(shù)據(jù)碧查。二進(jìn)制數(shù)據(jù)一定要包在NSData對象中。如果要寫入其他類型的數(shù)據(jù),那么必須是屬性列表對象——也就是說忠售,是如下類型的對象:NSString传惠, NSArray, NSDictionary, NSDate, NSNumber, 或者 NSURL。更多內(nèi)容稻扬,查看Property List Programming Guide
如果可以卦方,產(chǎn)生一個(gè)或更多該對象或數(shù)據(jù)的表達(dá)。例如腐螟,如果之前選中了一個(gè)UIImage對象愿汰,你可以使用UIImageJPEGRepresentation和UIImagePNGRepresentation函數(shù)來將該圖片轉(zhuǎn)換成不同的表示困后。
獲取剪切板對象乐纸。通常獲取通用剪切板,調(diào)用 generalPasteboard類方法摇予。
對于寫入剪切板的條目的每一種表示設(shè)置一個(gè)UTI汽绢。
-
寫入數(shù)據(jù)到剪切板的第一個(gè)位置,對于不同的數(shù)據(jù)類型:
- 如果是數(shù)據(jù)對象侧戴,發(fā)送setData:forPasteboardType: 消息到剪切板對象
- 如果是屬性列表對象宁昭,發(fā)送setValue:forPasteboardType: 消息到剪切板。
-
如果命令是剪切酗宋,從應(yīng)用的數(shù)據(jù)中移除選中的對象并更新你的頁面积仗。
- (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]; } }
粘貼選中內(nèi)容
當(dāng)用戶點(diǎn)擊粘貼命令是,系統(tǒng)調(diào)用了響應(yīng)者的paste:方法蜕猫。同樣寂曹,該消息也會從第一響應(yīng)者開始沿響應(yīng)鏈傳送。
實(shí)現(xiàn)paste:方法時(shí)回右,你從剪切板中以一種能夠支持的表示讀入對象隆圆。然后添加被粘貼對象到你的應(yīng)用中的數(shù)據(jù)中,并在頁面中展示翔烁。該操作包含以下步驟:
獲取一個(gè)剪切板對象
驗(yàn)證剪切板的第一個(gè)對象包含應(yīng)用能支持的表示渺氧。通過調(diào)用 containsPasteboardTypes:或者pasteboardTypes方法獲取所有表示。注意蹬屹,你需要在canPerformAction:withSender:中執(zhí)行該步驟侣背。
-
如果剪切板的第一個(gè)條目包含該應(yīng)用能夠處理的數(shù)據(jù),調(diào)用下面方法中的一個(gè)來讀數(shù)據(jù):
- dataForPasteboardType: 如果要讀的數(shù)據(jù)包含在NSData對象中慨默,調(diào)用此方法贩耐。
- valueForPasteboardType: 如果要讀的數(shù)據(jù)為屬性列表數(shù)據(jù),調(diào)用此方法业筏。
將該對象添加到應(yīng)用的數(shù)據(jù)中憔杨。
-
展示該數(shù)據(jù)。
- (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]; } } }
結(jié)束操作
當(dāng)cut:, copy: 或者 paste:方法返回時(shí)蒜胖,編輯菜單自動隱藏消别。你可以讓他保持可見抛蚤,具體可查看Dismissing the Edit Menu