iOS 精通UIPasteboard 貼上板
有時候我們可能需要複製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:));
}
//針對於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];
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setTargetRect:self.frame inView:self.superview];
[menu setMenuVisible:YES animated: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,貼上到位址列去,而我們可以在應用程式間“悄悄”的通訊、共享資料。
注:這裡的“悄悄”只是說其他的應用程式不知道,而系統是允許的。
我們用模板Single View Application來建立兩個簡單的工程,一個叫PasteBoardWrite,另一個叫PasteBoardRead,介面分別如下:
在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。
用自己建立的貼上板,能只在你的本地應用之間通訊,有時候它能讓你的使用者體驗變得更好,比如微信就是這麼做的。