一、內建剪下板操作的原生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
效果展示