一、自帶剪切板操作的原生UI控件
在iOS的UI系統中,有3個控件自帶剪切板操作,分別是UITextField、UITextView與UIWebView。在這些控件的文字交互處進行長按手勢可以在屏幕視圖上喚出系統的剪切板控件,用戶可以進行復制、粘貼,剪切等操作,其效果分別如下圖所示。
UITextField的文字操作
UITextView的文字操作
二、系統的剪切板管理類UIPasteboard
實際上,當用戶通過上面的空間進行復制、剪切等操作時,被選中的內容會被存放到系統的剪切板中,並且這個剪切板並不只能存放字符串數據,其還可以進行圖片數據與網址URL數據的存放。這個剪切板就是UIPasteboard類,開發者也可以直接通過它來操作數據進行應用內或應用間傳值。
UIPasteboard類有3個初始化方法,如下:
//獲取系統級別的剪切板 + (UIPasteboard *)generalPasteboard; //獲取一個自定義的剪切板 name參數為此剪切板的名稱 create參數用於設置當這個剪切板不存在時 是否進行創建 + (nullable UIPasteboard *)pasteboardWithName:(NSString *)pasteboardName create:(BOOL)create; //獲取一個應用內可用的剪切板 + (UIPasteboard *)pasteboardWithUniqueName;
上面3個初始化方法,分別獲取或創建3個級別不同的剪切板,系統級別的剪切板在整個設備中共享,即是應用程序被刪掉,其向系統級的剪切板中寫入的數據依然在。自定義的剪切板通過一個特定的名稱字符串進行創建,它在應用程序內或者同一開發者開發的其他應用程序中可以進行數據共享。第3個方法創建的剪切板等價為使用第2個方法創建的剪切板,只是其名稱字符串為nil,它通常用於當前應用內部。
注意:使用第3個方法創建的剪切板默認是不進行數據持久化的,及當應用程序退出後,剪切板中內容將別抹去。若要實現持久化,需要設置persistent屬性為YES。
UIPasteboard中常用方法及屬性如下:
//剪切板的名稱 @property(readonly,nonatomic) NSString *name; //根據名稱刪除一個剪切板 + (void)removePasteboardWithName:(NSString *)pasteboardName; //是否進行持久化 @property(getter=isPersistent,nonatomic) BOOL persistent; //此剪切板的改變次數 系統級別的剪切板只有當設備重新啟動時 這個值才會清零 @property(readonly,nonatomic) NSInteger changeCount;
下面這些方法用於設置與獲取剪切板中的數據:
最新一組數據對象的存取:
//獲取剪切板中最新數據的類型 - (NSArray<NSString *> *)pasteboardTypes; //獲取剪切板中最新數據對象是否包含某一類型的數據 - (BOOL)containsPasteboardTypes:(NSArray<NSString *> *)pasteboardTypes; //將剪切板中最新數據對象某一類型的數據取出 - (nullable NSData *)dataForPasteboardType:(NSString *)pasteboardType; //將剪切板中最新數據對象某一類型的值取出 - (nullable id)valueForPasteboardType:(NSString *)pasteboardType; //為剪切板中最新數據對應的某一數據類型設置值 - (void)setValue:(id)value forPasteboardType:(NSString *)pasteboardType; //為剪切板中最新數據對應的某一數據類型設置數據 - (void)setData:(NSData *)data forPasteboardType:(NSString *)pasteboardType; 多組數據對象的存取: //數據組數 @property(readonly,nonatomic) NSInteger numberOfItems; //獲取一組數據對象包含的數據類型 - (nullable NSArray *)pasteboardTypesForItemSet:(nullable NSIndexSet*)itemSet; //獲取一組數據對象中是否包含某些數據類型 - (BOOL)containsPasteboardTypes:(NSArray<NSString *> *)pasteboardTypes inItemSet:(nullable NSIndexSet *)itemSet; //根據數據類型獲取一組數據對象 - (nullable NSIndexSet *)itemSetWithPasteboardTypes:(NSArray *)pasteboardTypes; //根據數據類型獲取一組數據的值 - (nullable NSArray *)valuesForPasteboardType:(NSString *)pasteboardType inItemSet:(nullable NSIndexSet *)itemSet; //根據數據類型獲取一組數據的NSData數據 - (nullable NSArray *)dataForPasteboardType:(NSString *)pasteboardType inItemSet:(nullable NSIndexSet *)itemSet; //所有數據對象 @property(nonatomic,copy) NSArray *items; //添加一組數據對象 - (void)addItems:(NSArray<NSDictionary<NSString *, id> *> *)items;
上面方法中很多需要傳入數據類型參數,這些參數是系統定義好的一些字符竄,如下:
//所有字符串類型數據的類型定義字符串數組 UIKIT_EXTERN NSArray<NSString *> *UIPasteboardTypeListString; //所有URL類型數據的類型定義字符串數組 UIKIT_EXTERN NSArray<NSString *> *UIPasteboardTypeListURL; //所有圖片數據的類型定義字符串數據 UIKIT_EXTERN NSArray<NSString *> *UIPasteboardTypeListImage; //所有顏色數據的類型定義字符串數組 UIKIT_EXTERN NSArray<NSString *> *UIPasteboardTypeListColor;
相比於上面兩組方法,下面這些方法更加面向對象,在開發中使用更加方便與快捷:
//獲取或設置剪切板中的字符串數據 @property(nullable,nonatomic,copy) NSString *string; //獲取或設置剪切板中的字符串數組 @property(nullable,nonatomic,copy) NSArray<NSString *> *strings; //獲取或設置剪切板中的URL數據 @property(nullable,nonatomic,copy) NSURL *URL; //獲取或設置剪切板中的URL數組 @property(nullable,nonatomic,copy) NSArray<NSURL *> *URLs; //獲取或s何止剪切板中的圖片數據 @property(nullable,nonatomic,copy) UIImage *image; //獲取或設置剪切板中的圖片數組 @property(nullable,nonatomic,copy) NSArray<UIImage *> *images; //獲取或設置剪切板中的顏色數據 @property(nullable,nonatomic,copy) UIColor *color; //獲取或設置剪切板中的顏色數組 @property(nullable,nonatomic,copy) NSArray<UIColor *> *colors; 對剪切板的某些操作會觸發如下通知: //剪切板內容發生變化時發送的通知 UIKIT_EXTERN NSString *const UIPasteboardChangedNotification; //剪切板數據類型鍵值增加時發送的通知 UIKIT_EXTERN NSString *const UIPasteboardChangedTypesAddedKey; //剪切板數據類型鍵值移除時發送的通知 UIKIT_EXTERN NSString *const UIPasteboardChangedTypesRemovedKey; //剪切板被刪除時發送的通知 UIKIT_EXTERN NSString *const UIPasteboardRemovedNotification;
三、復制圖片的簡單例子
創建一個CopyView
#import "CopyView.h" @interface CopyView () @property (strong, nonatomic) UIImageView* img1; @property (strong, nonatomic) UIImageView* img2; @end @implementation CopyView -(UIImageView *)img1{ if (_img1 == nil) { _img1 = [[UIImageView alloc] initWithFrame:CGRectMake(10.0f, 20.0f, 100.0f, 100.0f)]; NSString* path = [[NSBundle mainBundle] pathForResource:@"NetworldImage" ofType:@"jpg"]; _img1.image = [UIImage imageWithContentsOfFile:path]; } return _img1; } -(UIImageView *)img2{ if (_img2 == nil) { _img2 = [[UIImageView alloc] initWithFrame:CGRectMake(CGRectGetMaxX(self.img1.frame)+50.0f, 20.0f, 100.0f, 100.0f)]; _img2.backgroundColor = [UIColor lightGrayColor]; } return _img2; } - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.backgroundColor = [UIColor whiteColor]; [self addSubview:self.img1]; [self addSubview:self.img2]; } return self; } -(BOOL)canBecomeFirstResponder{ return YES; } -(BOOL)canPerformAction:(SEL)action withSender:(id)sender{ NSArray* methodNameArr = @[@"copy:",@"cut:",@"select:",@"selectAll:",@"paste:"]; if ([methodNameArr containsObject:NSStringFromSelector(action)]) { return YES; } return [super canPerformAction:action withSender:sender]; } -(void)copy:(id)sender{ UIPasteboard* pasteboard = [UIPasteboard generalPasteboard]; [pasteboard setImage:self.img1.image]; } -(void)paste:(id)sender{ UIPasteboard* pasteboard = [UIPasteboard generalPasteboard]; self.img2.image = [pasteboard image]; } -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ [self becomeFirstResponder]; UIMenuController* menuController = [UIMenuController sharedMenuController]; [menuController setTargetRect:self.img1.frame inView:self]; [menuController setMenuVisible:YES animated:YES]; } @end 在controller中 #import "ViewController.h" #import "CopyView.h" @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; CopyView* cv = [[CopyView alloc] initWithFrame:self.view.bounds]; self.view = cv; } @end
效果展示