在iOS中下面三個控制項,自身就有複製-粘貼的功能:
1、UITextView
2、UITextField
3、UIWebView
UIKit framework提供了幾個類和協議方便我們在自己的應用程式中實現剪貼簿的功能。
1、UIPasteboard:我們可以向其中寫入資料,也可以讀取資料
2、UIMenuController:顯示一個捷徑功能表,用來展示複製、剪貼、粘貼等選擇的項。
3、UIResponder中的 canPerformAction:withSender:用於控制哪些命令顯示在捷徑功能表中。
4、當捷徑功能表上的命令點擊的時候,UIResponderStandardEditActions將會被調用。
下面這些項能被放置到剪貼簿中
1、UIPasteboardTypeListString — 字串數組, 包含kUTTypeUTF8PlainText
2、UIPasteboardTypeListURL — URL數組,包含kUTTypeURL
3、UIPasteboardTypeListImage — 圖形數組, 包含kUTTypePNG 和kUTTypeJPEG
4、UIPasteboardTypeListColor — 顏色數組
剪貼簿的類型分為兩種:
系統級:使用UIPasteboardNameGeneral和UIPasteboardNameFind,系統級應用程式關閉,或者卸載的資料不會丟失。
應用程式級:通過設定,可以讓資料在應用程式關閉之後仍然儲存在剪貼簿中,但是應用程式卸載之後資料就會失去。我們可用通過pasteboardWithName:create:來建立。
例子如下:
有時候我們可能需要複製UILabel上的文本,或者UIImageView的圖片,而UILabel和UIImageView預設是不響應Touch事件的,也無法複製,那麼我們就需要自己實現一個可複製的UILabel。新添加一個類繼承自UILabel:
@interface UICopyLabel : UILabel @end #import "UICopyLabel.h" @implementation UICopyLabel @end
為了能接收到事件(能成為第一響應者),我們需要覆蓋一個方法:
-(BOOL)canBecomeFirstResponder{ return YES; }
還需要針對複製的操作覆蓋兩個方法:
// 可以響應的方法-(BOOL)canPerformAction:(SEL)action withSender:(id)sender{ return (action == @selector(copy:)); }
//針對於回應程式法的實現 -(void)copy:(id)sender{ UIPasteboard *pboard = [UIPasteboard generalPasteboard]; pboard.string = self.text; }
有了以上三個方法,我們就能處理copy了,當然,在能接收到事件的情況下:
//UILabel預設是不接收事件的,我們需要自己添加touch事件 -(void)attachTapHandler{ self.userInteractionEnabled = YES; //使用者互動的總開關 UITapGestureRecognizer *touch = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; touch.numberOfTapsRequired = 2; [self addGestureRecognizer:touch]; [touch release]; } //綁定事件 - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self attachTapHandler]; } return self; } //同上 -(void)awakeFromNib{ [super awakeFromNib]; [self attachTapHandler]; }
我們已經可以接收到事件了!由於我在上方將tap數設為2,所以需要雙擊才能捕獲,接下來,我們需要處理這個tap,以便讓功能表列彈出來:
-(void)handleTap:(UIGestureRecognizer*) recognizer{ [self becomeFirstResponder]; UIMenuItem *copyLink = [[[UIMenuItemalloc] initWithTitle:@"複製" action:@selector(copy:)]autorelease]; [[UIMenuControllersharedMenuController] setMenuItems:[NSArrayarrayWithObjects:copyLink, nil]]; [[UIMenuControllersharedMenuController] setTargetRect:self.frameinView:self.superview]; [[UIMenuControllersharedMenuController] setMenuVisible:YESanimated: YES];}
這樣一來,一個可複製的UILabel就誕生了!它能處理接收點擊、快顯功能表欄、處理copy,這是一個很普通的可複製控制項。
接下來我們做一個可複製的UIImageView,建立一個新的viewController,放兩個imageView,預設顯示不同的圖:
然後把上面的代碼直接拷過來,改三個地方:
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender{ return (action == @selector(copy:) || action == @selector(paste:)); } -(void)copy:(id)sender{ UIPasteboard *pboard = [UIPasteboard generalPasteboard]; pboard.image = self.image; } -(void)paste:(id)sender{ UIPasteboard *pboard = [UIPasteboard generalPasteboard]; self.image = pboard.image; }
UIPasteboard有系統層級和應用層級兩種類型,所以不僅可以在應用程式內通訊,還能在應用程式間通訊,比如我複製一個url,然後開啟safari,粘貼到地址欄去,而我們可以在應用程式間通訊、共用資料。
在PasteBoardWrite裡面點“寫入”後把textField中的文本寫入粘貼板,然後切換到PasteBoardRead的時候顯示出來。如果我們的粘貼板只想給“自己人”用的話,就不能用系統的通用粘貼板,需要我們自己建立一個:
//需要提供一個唯一的名字,一般使用倒寫的網域名稱:com.mycompany.myapp.pboard //後面的參數表示,如果不存在,是否建立一個 UIPasteboard *pb = [UIPasteboard pasteboardWithName:@"testBoard" create:YES];
使用這個粘貼板,我們可以把文本存進去,然後在另一個app裡面讀出來,一些常用的類型已經被設定為屬性了:
除此之外,如果是能夠轉換成plist的資料類型(NSString, NSArray, NSDictionary, NSDate, NSNumber 和 NSURL),我們可以調用setValue:forPasteboardType:方法去儲存資料,其他類型只能調用setData:forPasteboardType:方法(plist資料類型也可使用),類似於這樣:
//儲存資料NSDictionary *dict = [NSDictionary dictionaryWithObject:textField.text forKey:@"content"]; NSData *dictData = [NSKeyedArchiver archivedDataWithRootObject:dict]; [pb setData:dictData forPasteboardType:@"myType"]; //擷取就類似於這樣: UIPasteboard *pb = [UIPasteboard pasteboardWithName:@"testBoard" create:YES]; NSDictionary *dict = [NSKeyedUnarchiver unarchiveObjectWithData:[pb dataForPasteboardType:@"myType"]]; caption.text = [dict objectForKey:@"content"];
上面提到了一個PasteboardType,這是一個統一類型標識符(Uniform Type Identifier UTI),能協助app擷取自己能處理的資料。比如你只能處理文本的粘貼,那給你一個UIImage顯然是無用的。你可以使用公用的UTI,也可以使用任一字元,蘋果建議使用倒寫的網域名稱加上類型名:com.myCompany.myApp.myType。