溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

iOS11如何實(shí)現(xiàn)拖拽交互

發(fā)布時(shí)間:2021-08-26 14:19:44 來(lái)源:億速云 閱讀:158 作者:小新 欄目:移動(dòng)開(kāi)發(fā)

這篇文章將為大家詳細(xì)講解有關(guān)iOS11如何實(shí)現(xiàn)拖拽交互,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

一、引言

在使用PC進(jìn)行操作時(shí),你一定遇到過(guò)這樣的場(chǎng)景,可以將圖片直接拖入聊天軟件進(jìn)行發(fā)送,可以將文檔、音樂(lè)、視頻文件等文件拖入相應(yīng)應(yīng)用程序直接進(jìn)行使用。這種拖拽操作交互極大的方便了電腦的使用。在iOS11中,你可以在iPhone或iPad上構(gòu)建這種交互體驗(yàn)!

說(shuō)在前面的話:

拖拽操作在iPad上是支持跨應(yīng)用程序的,你可以從一個(gè)應(yīng)用中拖取項(xiàng)目,通過(guò)Home鍵回到主界面并且打開(kāi)另一個(gè)應(yīng)用程序,然后將被拖拽的項(xiàng)目傳遞給這個(gè)應(yīng)用程序中。在iPhone上,拖拽操作只支持當(dāng)前應(yīng)用程序內(nèi),你可以將某個(gè)元素從一個(gè)界面拖拽到另一個(gè),這種維度的操作可以給設(shè)計(jì)人員更大的靈活性。

拖拽操作被設(shè)計(jì)成系統(tǒng)管理,開(kāi)發(fā)者不需要為App申請(qǐng)?zhí)厥獾挠脩魴?quán)限。   

二、拖拽源

對(duì)于拖拽操作,至少要有兩個(gè)組件,一個(gè)組件作為拖拽源用來(lái)提供數(shù)據(jù),一個(gè)組件作為拖拽目的用來(lái)接收數(shù)據(jù),當(dāng)前,同一個(gè)組件既可以是拖拽源也可以是拖拽目的。首先我們先來(lái)看拖拽源,在UIKit框架中,iOS11默認(rèn)實(shí)現(xiàn)了一些組件可以作為拖拽源, 例如UITextField、UITextView、UITableView和UICollectionView等。文本組件默認(rèn)支持拖拽操作進(jìn)行文本的傳遞,對(duì)于列表組件則默認(rèn)支持元素的拖拽。例如,在UITextField選中的文案中進(jìn)行拖拽,可以將文字拖拽出來(lái),效果如下圖:

iOS11如何實(shí)現(xiàn)拖拽交互

任意的UIView組件都可以作為拖拽源,讓其成為拖拽源其實(shí)也十分簡(jiǎn)單,只需要3步:

1.創(chuàng)建一個(gè)UIDragInteraction行為對(duì)象。

2.設(shè)置UIDragInteraction對(duì)象的代理并實(shí)現(xiàn)相應(yīng)方法。

3.將UIDragInteraction對(duì)象添加到指定View上。

最簡(jiǎn)單的可拖拽組件的創(chuàng)建示例代碼如下:

- (void)viewDidLoad {
  [super viewDidLoad];
  [self.view addSubview:self.dragView];
}
//創(chuàng)建View
-(UIView *)dragView{
  if (!_dragView) {
    _dragView = [[UIView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
    _dragView.backgroundColor = [UIColor redColor];
    [_dragView addInteraction:self.dragInteraction];
  }
  return _dragView;
}
//創(chuàng)建拖拽行為對(duì)象
-(UIDragInteraction *)dragInteraction{
  if (!_dragInteraction) {
    _dragInteraction = [[UIDragInteraction alloc]initWithDelegate:self];
    //要設(shè)置可用 注意!??!
    [_dragInteraction setEnabled:YES];
  }
  return _dragInteraction;
}

//實(shí)現(xiàn)提供數(shù)據(jù)的代理方法
- (NSArray<UIDragItem *> *)dragInteraction:(UIDragInteraction *)interaction itemsForBeginningSession:(id<UIDragSession>)session{
  //數(shù)據(jù)提供者
  NSItemProvider * provider = [[NSItemProvider alloc]initWithObject:@"Hello World"];
  UIDragItem * item = [[UIDragItem alloc]initWithItemProvider:provider];
  return @[item];
}

上面的dragInteraction:代理方法用來(lái)提供要傳遞的數(shù)據(jù),傳遞的數(shù)據(jù)必須遵守相應(yīng)的承諾協(xié)議,后面會(huì)給大家介紹,這里只是簡(jiǎn)單返回了一個(gè)字符串?dāng)?shù)據(jù)Hello World,運(yùn)行工程,你可以試驗(yàn)下,可以直接將我們自定義的視圖拖拽進(jìn)UITextField并在其中顯示Hello World。

三、關(guān)于UIDragInteraction類(lèi)

所有可以接收拖拽行為的組件都必須通過(guò)這個(gè)類(lèi)實(shí)現(xiàn),這個(gè)類(lèi)中屬性意義列舉如下:

//初始化方法
- (instancetype)initWithDelegate:(id<UIDragInteractionDelegate>)delegate;
//代理
@property (nonatomic, nullable, readonly, weak) id<UIDragInteractionDelegate> delegate;
//是否支持多種手勢(shì)都接收響應(yīng)
@property (nonatomic) BOOL allowsSimultaneousRecognitionDuringLift;
//設(shè)置是否有效
@property (nonatomic, getter=isEnabled) BOOL enabled;
//獲取默認(rèn)是否有效 不同的設(shè)備這個(gè)值將有所區(qū)別
@property (class, nonatomic, readonly, getter=isEnabledByDefault) BOOL enabledByDefault;

四、UIDragInteractionDelegate協(xié)議

UIDragInteractionDelegate用來(lái)處理拖拽源的行為與數(shù)據(jù)。其中定義了一個(gè)必須實(shí)現(xiàn)的方法和許多可選實(shí)現(xiàn)的方法。解析如下:

/*
這個(gè)方法是必須實(shí)現(xiàn)的用來(lái)返回拖拽源提供的數(shù)據(jù)
需要注意,這個(gè)函數(shù)需要返回一個(gè)數(shù)組,數(shù)組中可以有多個(gè)數(shù)據(jù)源
如果返回空數(shù)組,則拖拽行為不會(huì)開(kāi)始
*/
- (NSArray<UIDragItem *> *)dragInteraction:(UIDragInteraction *)interaction itemsForBeginningSession:(id<UIDragSession>)session;
/*
這個(gè)方法用來(lái)自定義拖拽效果的預(yù)覽視圖 關(guān)于預(yù)覽視圖,后面會(huì)介紹
需要注意,系統(tǒng)默認(rèn)會(huì)提供一個(gè)預(yù)覽視圖,不實(shí)現(xiàn)這個(gè)方法即是使用系統(tǒng)默認(rèn)的
如果返回nil,則會(huì)去除預(yù)覽動(dòng)畫(huà)
*/
- (nullable UITargetedDragPreview *)dragInteraction:(UIDragInteraction *)interaction previewForLiftingItem:(UIDragItem *)item session:(id<UIDragSession>)session;
/*
拖拽動(dòng)畫(huà)即將開(kāi)始時(shí)會(huì)調(diào)用此函數(shù)
*/
- (void)dragInteraction:(UIDragInteraction *)interaction willAnimateLiftWithAnimator:(id<UIDragAnimating>)animator session:(id<UIDragSession>)session;
//拖拽行為會(huì)話即將開(kāi)始時(shí)調(diào)用的方法
- (void)dragInteraction:(UIDragInteraction *)interaction sessionWillBegin:(id<UIDragSession>)session;
//這個(gè)方法設(shè)置數(shù)據(jù)的防止是否允許數(shù)據(jù)的 移動(dòng)操作,需要注意,這個(gè)只有在app內(nèi)有效,跨app的操作會(huì)總是復(fù)制數(shù)據(jù)
- (BOOL)dragInteraction:(UIDragInteraction *)interaction sessionAllowsMoveOperation:(id<UIDragSession>)session;
//設(shè)置是否允許跨應(yīng)用程序進(jìn)行拖拽 ipad
- (BOOL)dragInteraction:(UIDragInteraction *)interaction sessionIsRestrictedToDraggingApplication:(id<UIDragSession>)session;
//設(shè)置預(yù)覽視圖是否顯示原始大小
- (BOOL)dragInteraction:(UIDragInteraction *)interaction prefersFullSizePreviewsForSession:(id<UIDragSession>)session;
/*
當(dāng)拖拽源被移動(dòng)時(shí)調(diào)用,可以用如下方法獲取其坐標(biāo)
NSLog(@"%f,%f",[session locationInView:self.view].x,[session locationInView:self.view].y);
*/
- (void)dragInteraction:(UIDragInteraction *)interaction sessionDidMove:(id<UIDragSession>)session;
//拖拽行為將要結(jié)束時(shí)調(diào)用
- (void)dragInteraction:(UIDragInteraction *)interaction session:(id<UIDragSession>)session willEndWithOperation:(UIDropOperation)operation;
//拖拽行為已經(jīng)結(jié)束時(shí)調(diào)用
- (void)dragInteraction:(UIDragInteraction *)interaction session:(id<UIDragSession>)session didEndWithOperation:(UIDropOperation)operation;
//拖拽源進(jìn)行了放置操作后調(diào)用
- (void)dragInteraction:(UIDragInteraction *)interaction sessionDidTransferItems:(id<UIDragSession>)session;
//設(shè)置拖拽動(dòng)作取消的視圖動(dòng)畫(huà) 返回nil則消除動(dòng)畫(huà)
-(nullable UITargetedDragPreview *)dragInteraction:(UIDragInteraction *)interaction previewForCancellingItem:(UIDragItem *)item withDefault:(UITargetedDragPreview *)defaultPreview;
//拖拽動(dòng)作即將取消時(shí)調(diào)用的方法
- (void)dragInteraction:(UIDragInteraction *)interaction item:(UIDragItem *)item willAnimateCancelWithAnimator:(id<UIDragAnimating>)animator;
//設(shè)置是否允許向拖拽中的項(xiàng)目添加數(shù)據(jù)
/*
可以返回?cái)?shù)據(jù)載體數(shù)組 當(dāng)拖拽過(guò)程中 點(diǎn)擊可拖拽的組件時(shí)會(huì)觸發(fā)
*/
- (NSArray<UIDragItem *> *)dragInteraction:(UIDragInteraction *)interaction itemsForAddingToSession:(id<UIDragSession>)session withTouchAtPoint:(CGPoint)point;
//設(shè)置允許進(jìn)行拖拽中追加數(shù)據(jù)的拖拽行為會(huì)話
- (nullable id<UIDragSession>)dragInteraction:(UIDragInteraction *)interaction sessionForAddingItems:(NSArray<id<UIDragSession>> *)sessions withTouchAtPoint:(CGPoint)point;
//將要向拖拽組件中追加數(shù)據(jù)時(shí)調(diào)用
- (void)dragInteraction:(UIDragInteraction *)interaction session:(id<UIDragSession>)session willAddItems:(NSArray<UIDragItem *> *)items forInteraction:(UIDragInteraction *)addingInteraction;

上面列舉的協(xié)議方法中有關(guān)聯(lián)到其他許多iOS11中新增的類(lèi),后面會(huì)一一介紹。其實(shí),完成了以上內(nèi)容的了解,你就已經(jīng)可以完全隨心所欲的定制拖拽源組件了。

五、放置目的地

拖拽源是數(shù)據(jù)的提供者,放置目的地就是數(shù)據(jù)的接收者。前面我們也實(shí)驗(yàn)過(guò),將自定義的拖拽源拖拽進(jìn)UITextField后,文本框中會(huì)自動(dòng)填充我們提供的文本數(shù)據(jù)。同樣,對(duì)于任何自定義的UIView視圖,我們也可以讓其成為放置目的地,需要完成如下3步:

1.創(chuàng)建一個(gè)UIDropInteraction行為對(duì)象。

2.設(shè)置UIDropInteraction對(duì)象的代理并實(shí)現(xiàn)協(xié)議方法。

3.將其添加到自定義的視圖中。

例如,我們將自定義的UILabel組件用來(lái)顯示拖拽的文案:

//添加視圖
- (void)viewDidLoad {
  [super viewDidLoad];
  //有關(guān)拖拽源的代碼 前面已經(jīng)列舉過(guò) 這里不再重復(fù)
  [self.view addSubview:self.dragView];
  [self.view addSubview:self.dropLabel];
}

-(UILabel *)dropLabel{
  if (!_dropLabel) {
    _dropLabel = [[UILabel alloc]initWithFrame:CGRectMake(10, 300, 300, 30)];
    _dropLabel.backgroundColor = [UIColor greenColor];
    _dropLabel.userInteractionEnabled = YES;
    [_dropLabel addInteraction:self.dropInteraction];
  }
  return _dropLabel;
}
//放置目的地行為對(duì)象
-(UIDropInteraction*)dropInteraction{
  if (!_dropInteraction) {
    _dropInteraction = [[UIDropInteraction alloc]initWithDelegate:self];
  }
  return _dropInteraction;
}

//這個(gè)方法返回是否響應(yīng)此放置目的地的放置請(qǐng)求
-(BOOL)dropInteraction:(UIDropInteraction *)interaction canHandleSession:(id<UIDropSession>)session{
  return YES;
}
//設(shè)置以何種方式響應(yīng)拖放會(huì)話行為
-(UIDropProposal *)dropInteraction:(UIDropInteraction *)interaction sessionDidUpdate:(id<UIDropSession>)session{
  return [[UIDropProposal alloc]initWithDropOperation:UIDropOperationCopy];
}
//已經(jīng)應(yīng)用拖放行為后執(zhí)行的操作
-(void)dropInteraction:(UIDropInteraction *)interaction performDrop:(id<UIDropSession>)session{ 
  [session loadObjectsOfClass:[NSString class] completion:^(NSArray<__kindof id<NSItemProviderReading>> * _Nonnull objects) {
    self.dropLabel.text = objects.firstObject;
  }];
}

上面的代碼將我們自定義的拖拽源提供的Hello World拖放進(jìn)了UILabel組件中。

六、關(guān)于UIDropInteraction類(lèi)

與UIDragInteraction類(lèi)類(lèi)似,這個(gè)類(lèi)的作用是讓組件有相應(yīng)放置操作的能力。其中屬性如下:

//初始化方法
- (instancetype)initWithDelegate:(id<UIDropInteractionDelegate>)delegate;
//代理對(duì)象
@property (nonatomic, nullable, readonly, weak) id<UIDropInteractionDelegate> delegate;
//是否允許多個(gè)交互行為
@property (nonatomic, assign) BOOL allowsSimultaneousDropSessions;

七、UIDropInteractionDelegate協(xié)議

UIDropInteractionDelegate協(xié)議中所定義的方法全部是可選實(shí)現(xiàn)的,其用來(lái)處理用戶放置交互行為。

//放置行為即將響應(yīng)時(shí)觸發(fā)的方法 返回值確定是否響應(yīng)此次行為
- (BOOL)dropInteraction:(UIDropInteraction *)interaction canHandleSession:(id<UIDropSession>)session;
//當(dāng)上面的協(xié)議方法返回YES時(shí)會(huì)接著調(diào)用這個(gè)函數(shù)
- (void)dropInteraction:(UIDropInteraction *)interaction sessionDidEnter:(id<UIDropSession>)session;
//將要處理數(shù)據(jù)時(shí)回調(diào)的方法
/*
當(dāng)數(shù)據(jù)源數(shù)據(jù)添加時(shí),這個(gè)方法也會(huì)被重新調(diào)用 
這個(gè)函數(shù)需要返回一個(gè)處理行為方式UIDropProposal對(duì)象,這個(gè)我們后面再說(shuō)
*/
- (UIDropProposal *)dropInteraction:(UIDropInteraction *)interaction sessionDidUpdate:(id<UIDropSession>)session;
//放置行為相應(yīng)結(jié)束的時(shí)候會(huì)調(diào)用此方法
- (void)dropInteraction:(UIDropInteraction *)interaction sessionDidExit:(id<UIDropSession>)session;
//這個(gè)方法當(dāng)用戶進(jìn)行放置時(shí)會(huì)調(diào)用,可以從session中獲取被傳遞的數(shù)據(jù)
- (void)dropInteraction:(UIDropInteraction *)interaction performDrop:(id<UIDropSession>)session;
//放置動(dòng)畫(huà)完成后會(huì)調(diào)用這個(gè)方法
- (void)dropInteraction:(UIDropInteraction *)interaction concludeDrop:(id<UIDropSession>)session;
//整個(gè)拖放行為結(jié)束后會(huì)調(diào)用
- (void)dropInteraction:(UIDropInteraction *)interaction sessionDidEnd:(id<UIDropSession>)session;
//下面這些方法用來(lái)自定義放置動(dòng)畫(huà)
//設(shè)置放置預(yù)覽動(dòng)畫(huà)
- (nullable UITargetedDragPreview *)dropInteraction:(UIDropInteraction *)interaction previewForDroppingItem:(UIDragItem *)item withDefault:(UITargetedDragPreview *)defaultPreview;
//這個(gè)函數(shù)每當(dāng)有一個(gè)拖拽數(shù)據(jù)項(xiàng)放入時(shí)都會(huì)調(diào)用一次 可以進(jìn)行動(dòng)畫(huà)
- (void)dropInteraction:(UIDropInteraction *)interaction item:(UIDragItem *)item willAnimateDropWithAnimator:(id<UIDragAnimating>)animator;

需要注意,UIDropProposal類(lèi)用來(lái)進(jìn)行處理回執(zhí),屬性方法解析如下:

//初始化方法
/*
typedef NS_ENUM(NSUInteger, UIDropOperation) {
  //取消這次行為
  UIDropOperationCancel  = 0,
  //拒絕行為
  UIDropOperationForbidden = 1,
  //接收拷貝數(shù)據(jù)
  UIDropOperationCopy   = 2,
  //接收移動(dòng)數(shù)據(jù)
  UIDropOperationMove   = 3,
}
*/
- (instancetype)initWithDropOperation:(UIDropOperation)operation;
//處理方式
@property (nonatomic, readonly) UIDropOperation operation;
//精準(zhǔn)定位
@property (nonatomic, getter=isPrecise) BOOL precise;
//設(shè)置是否展示完整的預(yù)覽尺寸
@property (nonatomic) BOOL prefersFullSizePreview;

八、拖拽數(shù)據(jù)載體UIDragItem類(lèi)

UIDragItem類(lèi)用來(lái)承載要傳遞的數(shù)據(jù)。其通過(guò)NSItemProvider類(lèi)來(lái)進(jìn)行構(gòu)建,傳遞的數(shù)據(jù)類(lèi)型是有嚴(yán)格規(guī)定的,必須遵守一定的協(xié)議,系統(tǒng)的NSString,NSAttributeString,NSURL,UIColor和UIImage是默認(rèn)支持的,你可以直接傳遞這些數(shù)據(jù)。

UIDragItem中提供的屬性方法:

//初始化方法
- (instancetype)initWithItemProvider:(NSItemProvider *)itemProvider;
//數(shù)據(jù)提供者實(shí)例
@property (nonatomic, readonly) __kindof NSItemProvider *itemProvider;
//用來(lái)傳遞一些額外的關(guān)聯(lián)信息
@property (nonatomic, strong, nullable) id localObject;
//用來(lái)自定義每個(gè)item添加時(shí)的預(yù)覽動(dòng)畫(huà)
@property (nonatomic, copy, nullable) UIDragPreview * _Nullable (^previewProvider)(void);

九、UIDropSession與UIDragSession

在與拖拽交互相關(guān)的接口中,這兩個(gè)是面向協(xié)議編程的絕佳范例,首先在UIKit框架中只定義了這兩個(gè)協(xié)議,而并沒(méi)有相關(guān)的實(shí)現(xiàn)類(lèi),在拖拽行為的相關(guān)回調(diào)接口中,很多id類(lèi)型的參數(shù)都遵守了這個(gè)協(xié)議,我們無(wú)需知道是哪個(gè)類(lèi)實(shí)現(xiàn)的,直接進(jìn)行使用即可:

UIDropSession:

//繼承于UIDragDropSession(提供基礎(chǔ)數(shù)據(jù)), NSProgressReporting(提供數(shù)據(jù)讀取進(jìn)度)
@protocol UIDropSession <UIDragDropSession, NSProgressReporting>
//原始的dragSesstion會(huì)話 如果是跨應(yīng)用的 則為nil
@property (nonatomic, readonly, nullable) id<UIDragSession> localDragSession;
//設(shè)置進(jìn)度風(fēng)格
/*
typedef NS_ENUM(NSUInteger, UIDropSessionProgressIndicatorStyle) {
  UIDropSessionProgressIndicatorStyleNone,    // 無(wú)
  UIDropSessionProgressIndicatorStyleDefault,  // 默認(rèn)的
} API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(watchos, tvos);
*/
@property (nonatomic) UIDropSessionProgressIndicatorStyle progressIndicatorStyle;
//進(jìn)行數(shù)據(jù)的加載
- (NSProgress *)loadObjectsOfClass:(Class<NSItemProviderReading>)aClass completion:(void(^)(NSArray<__kindof id<NSItemProviderReading>> *objects))completion;
@end

UIDragSession:

API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(watchos, tvos) @protocol UIDragSession <UIDragDropSession>
//設(shè)置要傳遞的額外信息 只有在同個(gè)APP內(nèi)可見(jiàn)
@property (nonatomic, strong, nullable) id localContext;
@end

UIDragDropSession:

//傳遞的數(shù)據(jù)數(shù)組
@property (nonatomic, readonly) NSArray<UIDragItem *> *items;
//當(dāng)前操作行為的坐標(biāo)
- (CGPoint)locationInView:(UIView *)view;
//此次行為是否允許移動(dòng)操作
@property (nonatomic, readonly) BOOL allowsMoveOperation;
//是否支持應(yīng)用程序?qū)用娴耐献?
@property (nonatomic, readonly, getter=isRestrictedToDraggingApplication) BOOL restrictedToDraggingApplication;
//驗(yàn)證傳遞的數(shù)據(jù)是否支持某個(gè)數(shù)據(jù)類(lèi)型協(xié)議
- (BOOL)hasItemsConformingToTypeIdentifiers:(NSArray<NSString *> *)typeIdentifiers;
//驗(yàn)證傳遞的數(shù)據(jù)是否可以加載某個(gè)類(lèi)
- (BOOL)canLoadObjectsOfClass:(Class<NSItemProviderReading>)aClass;

十、交互預(yù)覽類(lèi)UITargetedDragPreview

UITargetedDragPreview專(zhuān)門(mén)用來(lái)處理拖放交互過(guò)程中的動(dòng)畫(huà)與預(yù)覽視圖。方法解析如下:

//創(chuàng)建一個(gè)預(yù)覽對(duì)象 
/*
view:要?jiǎng)?chuàng)建的預(yù)覽視圖 需要注意,這個(gè)視圖必須在window上
param:配置參數(shù)
target:容器視圖,用來(lái)展示預(yù)覽,一般設(shè)置為view的父視圖
*/
- (instancetype)initWithView:(UIView *)view parameters:(UIDragPreviewParameters *)parameters target:(UIDragPreviewTarget *)target;
//同上
-(instancetype)initWithView:(UIView *)view parameters:(UIDragPreviewParameters *)parameters;
//同上
- (instancetype)initWithView:(UIView *)view;
//動(dòng)畫(huà)承載者
@property (nonatomic, readonly) UIDragPreviewTarget* target;
//動(dòng)畫(huà)視圖
@property (nonatomic, readonly) UIView *view;
//配置參數(shù)
@property (nonatomic, readonly, copy) UIDragPreviewParameters *parameters;
//尺寸
@property (nonatomic, readonly) CGSize size;
//返回新的對(duì)象
- (UITargetedDragPreview *)retargetedPreviewWithTarget:(UIDragPreviewTarget *)newTarget;

UIDragPreviewTarget主要用來(lái)設(shè)置動(dòng)畫(huà)的起始視圖與結(jié)束時(shí)回歸的視圖,其中屬性方法如下:

/*
初始化方法
container:必須是在window上的view
center:動(dòng)畫(huà)起點(diǎn)與終點(diǎn)
transform:進(jìn)行變換
*/
- (instancetype)initWithContainer:(UIView *)container center:(CGPoint)center transform:(CGAffineTransform)transform;
//同上
- (instancetype)initWithContainer:(UIView *)container center:(CGPoint)center;
//對(duì)應(yīng)屬性
@property (nonatomic, readonly) UIView *container;
@property (nonatomic, readonly) CGPoint center;
@property (nonatomic, readonly) CGAffineTransform transform;

UIDragPreviewParameters用來(lái)進(jìn)行拖拽動(dòng)畫(huà)的配置,解析如下:

//構(gòu)造方法并設(shè)置路徑矩形
- (instancetype)initWithTextLineRects:(NSArray<NSValue /* CGRect */ *> *)textLineRects;
//顯示的路徑
@property (nonatomic, copy, nullable) UIBezierPath *visiblePath;
//背景色
@property (nonatomic, copy, null_resettable) UIColor *backgroundColor;

我們可以使用任意自定義的視圖來(lái)展現(xiàn)這個(gè)預(yù)覽動(dòng)畫(huà),如下圖所示:

iOS11如何實(shí)現(xiàn)拖拽交互

十一、使用拖拽操作進(jìn)行自定義數(shù)據(jù)的傳遞

本篇文章到這里,其實(shí)基本的內(nèi)容都已經(jīng)說(shuō)完了,雖然比較詳細(xì),也可能難免冗余,如果你耐著性子看到了這里,那么我首先欽佩你的毅力并且感謝你的耐心。其實(shí),拖拽交互如果進(jìn)行只能對(duì)系統(tǒng)的提供的數(shù)據(jù)類(lèi)型進(jìn)行操作則應(yīng)用就局限太多。試想一下,如果我們可以通過(guò)拖拽商品來(lái)進(jìn)行購(gòu)買(mǎi),拖拽聯(lián)系人來(lái)進(jìn)行發(fā)送,或者在游戲中,拖拽進(jìn)行卡片的融合,裝備的提煉等等這種交互操作是不是會(huì)很暢快。最后,我們就來(lái)看看如何讓自定義的數(shù)據(jù)類(lèi)型支持拖拽操作。

首先你需要關(guān)注兩個(gè)協(xié)議,NSItemProviderWriting與NSItemProviderReading。Writing協(xié)議用來(lái)讓數(shù)據(jù)支持提供給數(shù)據(jù)源,Reading協(xié)議讓數(shù)據(jù)支持從數(shù)據(jù)源讀出,用自定義的Person類(lèi)為例:

#import <Foundation/Foundation.h>
//遵守協(xié)議
@interface Person : NSObject<NSItemProviderWriting,NSItemProviderReading>
//自定義內(nèi)容
@property(nonatomic,strong)NSString * name;
@property(nonatomic,assign)NSUInteger age;
@end
//.m文件
@implementation Person
//數(shù)據(jù)歸檔
- (nullable NSProgress *)loadDataWithTypeIdentifier:(NSString *)typeIdentifier
          forItemProviderCompletionHandler:(void (^)(NSData * _Nullable data, NSError * _Nullable error))completionHandler{
  NSProgress * pro = [NSProgress new];
  NSData * data = [NSKeyedArchiver archivedDataWithRootObject:self];
  completionHandler(data,nil);
  return pro;
}

+(NSItemProviderRepresentationVisibility)itemProviderVisibilityForRepresentationWithTypeIdentifier:(NSString *)typeIdentifier{
  return NSItemProviderRepresentationVisibilityAll;
}

- (NSItemProviderRepresentationVisibility)itemProviderVisibilityForRepresentationWithTypeIdentifier:(NSString *)typeIdentifier{
  return NSItemProviderRepresentationVisibilityAll;
}
//提供一個(gè)標(biāo)識(shí)符
+(NSArray<NSString *> *)writableTypeIdentifiersForItemProvider{
  return @[@"object"];
}
-(NSArray<NSString *> *)writableTypeIdentifiersForItemProvider{
  return @[@"object"];
}

- (instancetype)initWithCoder:(NSCoder *)coder
{
  self = [super init];
  if (self) {
    self.name = [coder decodeObjectForKey:@"name"];
    self.age = [coder decodeIntegerForKey:@"age"];
  }
  return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder{
  [aCoder encodeObject:self.name forKey:@"name"];
  [aCoder encodeInteger:self.age forKey:@"age"];
}
//這兩個(gè)是讀協(xié)議
+(NSArray<NSString *> *)readableTypeIdentifiersForItemProvider{
  return @[@"object"];
}
//解歸檔返回
+ (nullable instancetype)objectWithItemProviderData:(NSData *)data
                   typeIdentifier:(NSString *)typeIdentifier
                       error:(NSError **)outError{
  Person * p = [NSKeyedUnarchiver unarchiveObjectWithData:data];
  return p;
}
@end

需要注意,在拖放行為讀取數(shù)據(jù)時(shí)的類(lèi)型要對(duì)應(yīng),如下:

-(void)dropInteraction:(UIDropInteraction *)interaction performDrop:(id<UIDropSession>)session{
  NSLog(@"%@",session.items.lastObject.localObject);
  [session loadObjectsOfClass:[Person class] completion:^(NSArray<__kindof id<NSItemProviderReading>> * _Nonnull objects) {
    self.dropLabel.text = ((Person*)objects.firstObject).name;
  }];
}

關(guān)于“iOS11如何實(shí)現(xiàn)拖拽交互”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI