史上第二走心的 iOS11 Drag & Drop 教程

話不多說,先上效果圖

普通view拖拽效果
TableView拖拽效果
CollectionView效果
muti-touch效果
多app交互

世界上最大的男性交友網(wǎng)站有demo

一.Tips:你必須要知道的概念

1. Drag 和 Drop 是什么呢?
  • 一種以圖形展現(xiàn)的方式把數(shù)據(jù)從一個 app 移動或拷貝到另一個 app(僅限iPad),或者在程序內(nèi)部進行
  • 充分利用了 iOS11 中新的文件系統(tǒng),只有在請求數(shù)據(jù)的時候才會去移動數(shù)據(jù)溃肪,而且保證只傳輸需要的數(shù)據(jù)
  • 通過異步的方式進行傳輸,這樣就不會阻塞runloop音五,從而保證在傳輸數(shù)據(jù)的時候用戶也有一個順暢的交互體驗
drag和drop的基本交互圖和支持的控件
2. 安全性:
  • 拖拽復(fù)制的過程不像剪切板那樣惫撰,而是保證數(shù)據(jù)只對目標app可見
  • 提供數(shù)據(jù)源的app可以限制本身的數(shù)據(jù)源只可在本 app 或者 公司組app 之間有權(quán)限使用,當(dāng)然也可以開放于所有 app躺涝,也支持企業(yè)用戶的管理配置
3. dragSession 的過程
  • Lift:用戶長按 item厨钻,item 脫離屏幕
  • Drag :用戶開始拖拽,此時可進行 自定義視圖預(yù)覽坚嗜、添加其他item添加內(nèi)容夯膀、懸停進行導(dǎo)航(即iPad 中打開別的app)
  • Set Down :此時用戶無非想進行兩種操作:取消拖拽 或者 在當(dāng)前手指離開的位置對 item 進行 drop 操作
  • Data Transfer :目標app 會向 源app 進行數(shù)據(jù)請求
  • 這些都是圍繞交互這一概念構(gòu)造的:即類似手勢識別器的概念,接收到用戶的操作后苍蔬,進行view層級的改變
4. Others
  • 需要給用戶提供 muti-touch 的使用诱建,這一點也是為了支持企業(yè)用戶的管理配置(比如一個手指選中一段文字,長按其處于lifting狀態(tài)碟绑,另外一個手指選中若干張圖片俺猿,然后打開郵件,把文字和圖片放進郵件格仲,視覺反饋是及時的押袍,動畫效果也很棒)
iPad 可實現(xiàn)的功能還是很豐富的

二、以CollectionView 為例凯肋,講一下整個拖拽的api使用情況

在API設(shè)計方面伯病,分為兩個步驟:Drag 和 Drop,對應(yīng)著兩套協(xié)議 UICollectionViewDragDelegate
UICollectionViewDropDelegate,因此在創(chuàng)建 CollectionView 的時候要增加以下代碼:

- (void)buildCollectionView {
    _collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:flowLayout];
    [_collectionView registerClass:[WPFImageCollectionViewCell class] forCellWithReuseIdentifier:imageCellIdentifier];
    _collectionView.delegate = self;
    _collectionView.dataSource = self;
    // 設(shè)置代理對象
    _collectionView.dragDelegate = self;
    _collectionView.dropDelegate = self;

    _collectionView.dragInteractionEnabled = YES;
    _collectionView.reorderingCadence = UICollectionViewReorderingCadenceImmediate;
    _collectionView.springLoaded = YES;
    _collectionView.backgroundColor = [UIColor whiteColor];
}
1. 創(chuàng)建CollectionView注意點總結(jié):
  • dragInteractionEnabled 屬性在 iPad 上默認是YES午笛,在 iPhone 默認是 NO惭蟋,只有設(shè)置為 YES 才可以進行 drag 操作

  • reorderingCadence (重排序節(jié)奏)可以調(diào)節(jié)集合視圖重排序的響應(yīng)性。 是 CollectionView 獨有的屬性(相對于UITableView)药磺,因為 其獨有的二維網(wǎng)格的布局告组,因此在重新排序的過程中有時候會發(fā)生元素回流了,有時候只是移動到別的位置癌佩,不想要這樣的效果木缝,就可以修改這個屬性改變其相應(yīng)性

    • UICollectionViewReorderingCadenceImmediate:默認值,當(dāng)開始移動的時候就立即回流集合視圖布局围辙,可以理解為實時的重新排序
    • UICollectionViewReorderingCadenceFast:如果你快速移動我碟,CollectionView 不會立即重新布局,只有在停止移動的時候才會重新布局
    • UICollectionViewReorderingCadenceSlow:停止移動再過一會兒才會開始回流姚建,重新布局
  • springLoaded :彈簧加載是一種導(dǎo)航和激活控件的方式矫俺,在整個系統(tǒng)中,當(dāng)處于 dragSession 的時候掸冤,只要懸浮在cell上面厘托,就會高亮,然后就會激活

    • UITableView 和 UICollectionView 都可以使用該方式加載稿湿,因為他們都遵守 UISpringLoadedInteractionSupporting 協(xié)議
    • 當(dāng)用戶在單元格使用彈性加載時铅匹,我們要選擇 CollectionView 或tableView 中的 item 或cell
    • 使用 - (BOOL)collectionView:shouldSpringLoadItemAtIndexPath:withContext:來自定義也是可以的
  • collectionView:itemsForAddingToDragSession: atIndexPath: :該方法是muti-touch對應(yīng)的方法

    • 當(dāng)接收到添加item響應(yīng)時,會調(diào)用該方法向已經(jīng)存在的drag會話中添加item
    • 如果需要饺藤,可以使用提供的點(在集合視圖的坐標空間中)進行其他命中測試包斑。
    • 如果該方法未實現(xiàn),或返回空數(shù)組涕俗,則不會將任何 item 添加到拖動舰始,手勢也會正常的響應(yīng)
- (NSArray<UIDragItem *> *)collectionView:(UICollectionView *)collectionView itemsForAddingToDragSession:(id<UIDragSession>)session atIndexPath:(NSIndexPath *)indexPath point:(CGPoint)point {
    NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithObject:self.dataSource[indexPath.item]];
    UIDragItem *item = [[UIDragItem alloc] initWithItemProvider:itemProvider];
    return @[item];
}
再放一遍這個效果圖
2. UICollectionViewDragDelegate(初始化和自定義拖動方法)
  • collectionView: itemsForBeginningDragSession:atIndexPath:提供一個 給定 indexPath 的可進行 drag 操作的 item(類似 hitTest: 方法周到該響應(yīng)的view )如果返回 nil,則不會發(fā)生任何拖拽事件

由于是返回一個數(shù)組咽袜,因此可以根據(jù)自己的需求來實現(xiàn)該方法:比如拖拽一個item,就可以把該組的所有 item 放進 dragSession 中枕稀,右上角會有小藍圈圈顯示個數(shù)(但是這種情況下要對數(shù)組進行重新排序询刹,因為數(shù)組中的最后一個元素會成為Lift 操作中的最上面的一個元素,排序后可以讓最先進入dragSession的item放在lift效果的最前面)

- (NSArray<UIDragItem *> *)collectionView:(UICollectionView *)collectionView itemsForBeginningDragSession:(id<UIDragSession>)session atIndexPath:(NSIndexPath *)indexPath {
    
    NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithObject:self.dataSource[indexPath.item]];
    UIDragItem *item = [[UIDragItem alloc] initWithItemProvider:itemProvider];
    self.dragIndexPath = indexPath;
    return @[item];
}
  • collectionView:dragPreviewParametersForItemAtIndexPath:允許對從取消或返回到 CollectionView 的 item 使用自定義預(yù)覽萎坷,如果該方法沒有實現(xiàn)或者返回nil凹联,那么整個 cell 將用于預(yù)覽
    • UIDragPreviewParameters 有兩個屬性:
      • backgroundColor 設(shè)置背景顏色,因為有的視圖本身就是半透明的哆档,添加背景色視覺效果更好
      • visiblePath設(shè)置視圖的可見區(qū)域蔽挠,比如可以自定義為圓角矩形或圖中的某一塊區(qū)域等,但是要注意裁剪的Rect 在目標視圖中必須要有意義;該屬性也要標記一下center方便進行定位
裁剪圖中的某一塊區(qū)域
選取的區(qū)域也可以大于這張圖澳淑,實現(xiàn)添加相框的效果
再高級的功能可以實現(xiàn)目標區(qū)域內(nèi)添加多個rect到dragSession
- (nullable UIDragPreviewParameters *)collectionView:(UICollectionView *)collectionView dragPreviewParametersForItemAtIndexPath:(NSIndexPath *)indexPath {
    // 可以在該方法內(nèi)使用 貝塞爾曲線 對單元格的一個具體區(qū)域進行裁剪
    UIDragPreviewParameters *parameters = [[UIDragPreviewParameters alloc] init];
    
    CGFloat previewLength = self.flowLayout.itemSize.width;
    CGRect rect = CGRectMake(0, 0, previewLength, previewLength);
    parameters.visiblePath = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:5];
    parameters.backgroundColor = [UIColor clearColor];
    return parameters;
}
  • 還有一些對于 drag 生命周期對應(yīng)的回調(diào)方法比原,可以在這些方法里添加各種動畫效果
/* 當(dāng) lift animation 完成之后開始拖拽之前會調(diào)用該方法
 * 該方法肯定會對應(yīng)著 -collectionView:dragSessionDidEnd: 的調(diào)用
 */
- (void)collectionView:(UICollectionView *)collectionView dragSessionWillBegin:(id<UIDragSession>)session {
    NSLog(@"dragSessionWillBegin --> drag 會話將要開始");
}

// 拖拽結(jié)束的時候會調(diào)用該方法
- (void)collectionView:(UICollectionView *)collectionView dragSessionDidEnd:(id<UIDragSession>)session {
    NSLog(@"dragSessionDidEnd --> drag 會話已經(jīng)結(jié)束");
}

當(dāng)然也可以在這些方法里面設(shè)置自定義的dragPreview,比如 iPad 中原生的通訊圖杠巡、地圖所展現(xiàn)的功能

在 dragSessionWillBegin 方法里面自定義 preview 視圖
3. UICollectionViewDropDelegate(遷移數(shù)據(jù)和自定義釋放動畫)
Drop手勢的流程圖
  • collectionView:performDropWithCoordinator: 方法使用 dropCoordinator 去置頂如果處理當(dāng)前 drop 會話的item 到指定的最終位置量窘, 同時也會根據(jù)drop item返回的數(shù)據(jù)更新數(shù)據(jù)源
    • 當(dāng)用戶開始進行 drop 操作的時候會調(diào)用這個方法
    • 如果該方法不做任何事,將會執(zhí)行默認的動畫
    • 注意:只有在這個方法中才可以請求到數(shù)據(jù)
    • 請求的方式是異步的氢拥,因此不要阻止數(shù)據(jù)的傳輸蚌铜,如果阻止時間過長,就不清楚數(shù)據(jù)要多久才能到達嫩海,系統(tǒng)甚至可能會kill掉你的應(yīng)用
- (void)collectionView:(UICollectionView *)collectionView performDropWithCoordinator:(id<UICollectionViewDropCoordinator>)coordinator {
    
    NSIndexPath *destinationIndexPath = coordinator.destinationIndexPath;
    UIDragItem *dragItem = coordinator.items.firstObject.dragItem;
    UIImage *image = self.dataSource[self.dragIndexPath.row];
    // 如果開始拖拽的 indexPath 和 要釋放的目標 indexPath 一致冬殃,就不做處理
    if (self.dragIndexPath.section == destinationIndexPath.section && self.dragIndexPath.row == destinationIndexPath.row) {
        return;
    }
    
    // 更新 CollectionView
    [collectionView performBatchUpdates:^{
        // 目標 cell 換位置
        [self.dataSource removeObjectAtIndex:self.dragIndexPath.item];
        [self.dataSource insertObject:image atIndex:destinationIndexPath.item];
        
        [collectionView moveItemAtIndexPath:self.dragIndexPath toIndexPath:destinationIndexPath];
    } completion:^(BOOL finished) {
        
    }];
    
    [coordinator dropItem:dragItem toItemAtIndexPath:destinationIndexPath];
}
  • collectionView: dropSessionDidUpdate: withDestinationIndexPath: 該方法是提供釋放方案的方法,雖然是optional叁怪,但是最好實現(xiàn)
    • 當(dāng) 跟蹤 drop 行為在 tableView 空間坐標區(qū)域內(nèi)部時會頻繁調(diào)用(因此要盡量減少這個方法的工作量审葬,否則幀率就會降低)
    • 當(dāng)drop手勢在某個section末端的時候,傳遞的目標索引路徑還不存在(此時 indexPath 等于 該 section 的行數(shù))骂束,這時候會追加到該section 的末尾
    • 在某些情況下耳璧,目標索引路徑可能為空(比如拖到一個沒有cell的空白區(qū)域)
    • 請注意,在某些情況下展箱,你的建議可能不被系統(tǒng)所允許旨枯,此時系統(tǒng)將執(zhí)行不同的建議
    • 你可以通過 -[session locationInView:] 做你自己的命中測試
    • UICollectionViewDropIntent對應(yīng)的三個枚舉值
      • UICollectionViewDropIntentUnspecified 將會接收drop,但是具體的位置要稍后才能確定混驰;不會開啟一個缺口攀隔,可以通過添加視覺效果給用戶傳達這一信息
      • UICollectionViewDropIntentInsertAtDestinationIndexPathdrop將會被插入到目標索引中;將會打開一個缺口栖榨,模擬最后釋放后的布局
      • UICollectionViewDropIntentInsertIntoDestinationIndexPathdrop 將會釋放在目標索引路徑昆汹,比如該cell是一個容器(集合),此時不會像 ?? 那個屬性一樣打開缺口婴栽,但是該條目標索引對應(yīng)的cell會高亮顯示
      • 補充:UITableView 在以上對應(yīng)枚舉值基礎(chǔ)上满粗,還有一個特有的 automatic 屬性,可以自動判斷是放入文件夾還是打開缺口進入目標索引
    • UIDropOperation對應(yīng)的四種狀態(tài)愚争。第四種 forbidden 是不允許在當(dāng)前位置drop:比如要把一個圖片放在一個文件夾內(nèi)映皆,但是這個文件夾是只讀的,就會出現(xiàn)這個圖標
- (UICollectionViewDropProposal *)collectionView:(UICollectionView *)collectionView dropSessionDidUpdate:(id<UIDropSession>)session withDestinationIndexPath:(nullable NSIndexPath *)destinationIndexPath {
    UICollectionViewDropProposal *dropProposal;
    // 如果是另外一個app轰枝,localDragSession為nil捅彻,此時就要執(zhí)行copy,通過這個屬性判斷是否是在當(dāng)前app中釋放鞍陨,當(dāng)然只有 iPad 才需要這個適配
    if (session.localDragSession) {
        dropProposal = [[UICollectionViewDropProposal alloc] initWithDropOperation:UIDropOperationCopy intent:UICollectionViewDropIntentInsertAtDestinationIndexPath];
    } else {
        dropProposal = [[UICollectionViewDropProposal alloc] initWithDropOperation:UIDropOperationCopy intent:UICollectionViewDropIntentInsertAtDestinationIndexPath];
    }
    return dropProposal;
}
  • collectionView:canHandleDropSession:通過該方法判斷對應(yīng)的item 能否被 執(zhí)行drop會話
    • 如果返回 NO步淹,將不會調(diào)用接下來的代理方法
    • 如果沒有實現(xiàn)該方法,那么默認返回 YES
- (BOOL)collectionView:(UICollectionView *)collectionView canHandleDropSession:(id<UIDropSession>)session {
    // 假設(shè)在該 drop 只能在當(dāng)前本 app中可執(zhí)行,在別的 app 中不可以
    if (session.localDragSession == nil) {
        return NO;
    }
    return YES;
}
  • collectionView: dropPreviewParametersForItemAtIndexPath: 當(dāng) item 執(zhí)行drop 操作的時候缭裆,可以自定義預(yù)覽圖
    • 如果沒有實現(xiàn)該方法或者返回nil键闺,整個cell將會被用于預(yù)覽圖
    • 該方法會經(jīng)由 -[UICollectionViewDropCoordinator dropItem:toItemAtIndexPath:]調(diào)用
    • 如果要去自定義占位drop,可以查看 UICollectionViewDropPlaceholder.previewParametersProvider
- (nullable UIDragPreviewParameters *)collectionView:(UICollectionView *)collectionView dropPreviewParametersForItemAtIndexPath:(NSIndexPath *)indexPath {

    return nil;
}
  • 當(dāng)然還有一些 常規(guī)的 drop 過程回調(diào)的方法
/* 當(dāng)drop會話進入到 collectionView 的坐標區(qū)域內(nèi)就會調(diào)用幼驶,
 * 早于- [collectionView dragSessionWillBegin] 調(diào)用
 */
- (void)collectionView:(UICollectionView *)collectionView dropSessionDidEnter:(id<UIDropSession>)session {
    NSLog(@"dropSessionDidEnter --> dropSession進入目標區(qū)域");
}

/* 當(dāng) dropSession 不在collectionView 目標區(qū)域的時候會被調(diào)用
 */
- (void)collectionView:(UICollectionView *)collectionView dropSessionDidExit:(id<UIDropSession>)session {
    NSLog(@"dropSessionDidExit --> dropSession 離開目標區(qū)域");
}

/* 當(dāng)dropSession 完成時會被調(diào)用艾杏,不管結(jié)果如何
 * 適合在這個方法里做一些清理的操作
 */
- (void)collectionView:(UICollectionView *)collectionView dropSessionDidEnd:(id<UIDropSession>)session {
    NSLog(@"dropSessionDidEnd --> dropSession 已完成");
}
4. 優(yōu)化
  • 涉及到app間拖動的時候,比如把相冊中照片拖到郵件中盅藻,為什么相冊中的小尺寸到了郵件中就剛剛和郵件中textView 寬度一致呢购桑?
    • 在方法collectionView:itemsForBeginningDragSession: atIndexPath: 中,通過設(shè)置itemProvider.preferredPresentationSize 來設(shè)置item執(zhí)行 drop 時的期望大小氏淑。這樣 郵件app 在后臺就能讀取到這個尺寸大小勃蜘,從而正常地顯示
5. Placeholder

這個在demo里沒寫,因為只有iPad才支持 app 間傳遞數(shù)據(jù)假残,我想史上第一走心的教程一定會詳細講述這個方法的

由于loadObject是異步的缭贡,因此加載數(shù)據(jù)和顯示preview是兩條不同的時間線
  • 使用場景:拖拽的item需要從服務(wù)器下載,比如拖拽相冊中存儲在iCloud 中的照片至郵件app中辉懒,就要先從 iCloud 下載阳惹,再進行下一步的展示,因此可能要等待一段時間才能下載完成眶俩,而且下載多個item還可能是亂序到達的莹汤。此時就需要PlaceHolder進行

  • 異步加載數(shù)據(jù)的時候可以用 PlaceHolder 推遲更新數(shù)據(jù)源直到數(shù)據(jù)加載完畢,從而保證UI 完全的響應(yīng)性颠印,不至于讓用戶長時間面對一個白板等待數(shù)據(jù)的傳輸

  • 如何創(chuàng)建PlaceHolder纲岭?通過釋放協(xié)調(diào)器dropCoordinator來創(chuàng)建,從而將其插入到占位符中线罕,并添加動畫

  • 使用PlaceHolder 注意事項:(app間拖拽的時候止潮,從A app 拖拽到 B app,確定位置之后钞楼,B中還未獲取到數(shù)據(jù)喇闸,加載數(shù)據(jù)的過程中展示占位動畫)

- (id<UICollectionViewDropPlaceholderContext>)dropItem:(UIDragItem *)dragItem toPlaceholder:(UICollectionViewDropPlaceholder*)placeholder;

  1. 不要使用 reloadData,使用 performBatchUpdates: 來替代(因為 reloadData 會重設(shè)一切询件,刪除一切 PlaceHolder)
  2. 可以使用 collectionView.hasUncommittedUpdates 來判斷當(dāng)前 CollectionView 是否還存在 PlaceHolder
6.數(shù)據(jù)傳輸(iPhone 開發(fā)者了解概念即可)
  • 所有的數(shù)據(jù)加載都是通過拖放實現(xiàn)的燃乍,NSITemProvider可以為你提供數(shù)據(jù)傳輸?shù)倪M度和取消操作
  • 提供數(shù)據(jù):
// 創(chuàng)建一個 NSItemProvider 對象,傳遞一個適用的對象
UIImage *image = [UIImage imageNamed:@"photo"];
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithObject:image];
  • 接收數(shù)據(jù)
    • loadObjectOfClass 返回一個progress
    • 調(diào)用一次loadObjectOfClass 只會返回一個特定的progress雳殊,通過KVO監(jiān)聽 UIDropSession.progress可以獲得所有的進度
    • demo是針對 iPhone 開發(fā)的,因此沒有具體實現(xiàn)
// 該方法中加載數(shù)據(jù)的方式是異步的窗轩,
NSProgress *progress = [itemProvider loadObjectOfClass:[UIImage class] completionHandler:^(id<NSItemProviderReading>  _Nullable object, NSError * _Nullable error) {
#waning 該回調(diào)在一個非主隊列進行夯秃,如果更新UI要回到主線程
        UIImage *image = (UIImage *)object;
        // 使用image
    }];
// 是否完成
BOOL isFinished = progress.isFinished;
// 當(dāng)前已完成進度
CGFloat progressSoFar = progress.fractionCompleted;
    
[progress cancel];
  • 注冊支持的文件類型ID的時候,最好具體到特定的類型,比如最好使用“public.png”代替“public.image”仓洼,“public.utf8-plain-text”代替“public.plain-text”介陶,當(dāng)然如果是僅支持公司內(nèi)部特定的app間傳遞,也可以完全自定義

  • 新概念:數(shù)據(jù)編組(Data Marshaling)

    • 提供數(shù)據(jù)有三種方式:

      • 直接提供NSData:itemProvider.registerDataRepresentation(...)
      • 提供一個文件或者文件夾:itemProvider.registerFileRepresentation(...fileOptions:[])
      • 作為 File Provider 的引用:itemProvider.registerFileRepresentation(...fileOptions:[.openInPlace])
    • 接收數(shù)據(jù)也有三種方式:

      • 直接拷貝出NSData 的副本:itemProvider.loadDataRepresentation(...)
      • 將文件或文件夾拷貝到自己的容器內(nèi):itemProvider.loadDataRepresentation(...)
      • 嘗試在本地打開文件:itemProvider.loadInPlaceFileRepresentation(...)
    • 數(shù)據(jù)編組直接做好了數(shù)據(jù)的轉(zhuǎn)換:

      • 提供者想要提供一個 NSData 類型數(shù)據(jù)色建,數(shù)據(jù)編組就直接將這個數(shù)據(jù)寫入文件并提供url的副本
      • 如果提供者提供的是文件夾哺呜,然后數(shù)據(jù)編組就會把文件壓縮并提供NSData
  • 最后稍微提到了File的另一個主題,也就是文件系統(tǒng)的拖拽箕戳,在這里大概敘述一下:

    • 文件的拖拽可以設(shè)置三種權(quán)限
      • 對所有人可見
      • 同一個 team 可見
      • 僅對自己可見
    • 文件的拖拽有兩種選項:
      • 直接提供副本
      • 提供url(意味著多個app可以共享一個文件)某残,對方修改,本地可以看到修改的地方

三. UIView-Tips

UITableView 的api使用基本和 UICollectionView 一致陵吸,在此不再贅述玻墅,但是以下UIView的特性還要再強調(diào)以下

  • iPhone 項目上,在對view添加UIDragInteraction操作時壮虫,一定要設(shè)置其enable 屬性為YES澳厢,否則不會響應(yīng)drag操作(iPhone默認為NO,iPad默認為YES)

  • UIDropProposal的屬性precise囚似,如果設(shè)置為YES剩拢,視圖的點擊測試區(qū)域?qū)⒙愿哂谟脩粲|摸位置,這能夠在視圖中進行更精確的放入饶唤,具體效果請看下圖

    • 當(dāng)然如果使用這個屬性的話要在 targetPoint 添加一些UI的提示徐伐,給用戶確切的反饋


      這樣就能精準地放入文本中的特定位置
  • prefersFullSizePreview,默認情況下預(yù)覽圖都是等比例縮小的搬素,因為過大是沒有意義的呵晨,遮擋屏幕就會影響到用戶交互,難以進行導(dǎo)航熬尺,但是有些時候也需要全尺寸的預(yù)覽圖(比如一個列表中需要重新布局摸屠,此時將整個列表縮小是沒有意義的)

    • 但是有些情況下,系統(tǒng)始終會進行比例縮小粱哼,即使是設(shè)置了全尺寸預(yù)覽
      • 組合拖動:如果添加多個項目進行拖動
      • 如果將item拖動到另外一個app季二,也肯定會等比例縮小
  • [itemProvider loadObjectOfClass: completionHandler:]

    • 該方法回調(diào)默認在主線程
    • 該方法返回一個progress,匯報加載的進度
    • 返回值 NSProgress 可以設(shè)置屬性 cancelled^cancellationHandler揭措,也可以進行斷點續(xù)傳操作胯舷,因為數(shù)據(jù)傳輸可能需要很久,需要給用戶取消的權(quán)利
    • 如果不想要顯示這個進度绊含,可以通過session.progressIndicatorStyle = UIDropSessionProgressIndicatorStyleNone; 來隱藏進度視圖桑嘶。
    • 也可以通過KVO監(jiān)聽progress實現(xiàn)自定義進度展示
??的方法控制效果

文章有點長,感謝您的閱讀躬充。
每個iOS開發(fā)人員都應(yīng)該了解的一篇非技術(shù)文章
demo地址

參考內(nèi)容:
Introducing Drag and Drop
Mastering Drag and Drop
Drag and Drop with Collection and Table View
Data Delivery with Drag and Drop

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末逃顶,一起剝皮案震驚了整個濱河市讨便,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌以政,老刑警劉巖霸褒,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異盈蛮,居然都是意外死亡废菱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門抖誉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來殊轴,“玉大人,你說我怎么就攤上這事寸五∈崃荩” “怎么了?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵梳杏,是天一觀的道長韧拒。 經(jīng)常有香客問我,道長十性,這世上最難降的妖魔是什么叛溢? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮劲适,結(jié)果婚禮上楷掉,老公的妹妹穿的比我還像新娘。我一直安慰自己霞势,他們只是感情好烹植,可當(dāng)我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著愕贡,像睡著了一般草雕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上固以,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天墩虹,我揣著相機與錄音,去河邊找鬼憨琳。 笑死诫钓,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的篙螟。 我是一名探鬼主播菌湃,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼遍略!你這毒婦竟也來了惧所?” 一聲冷哼從身側(cè)響起场梆,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎纯路,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體寞忿,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡驰唬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了腔彰。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叫编。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖霹抛,靈堂內(nèi)的尸體忽然破棺而出搓逾,到底是詐尸還是另有隱情,我是刑警寧澤杯拐,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布霞篡,位于F島的核電站,受9級特大地震影響端逼,放射性物質(zhì)發(fā)生泄漏朗兵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一顶滩、第九天 我趴在偏房一處隱蔽的房頂上張望余掖。 院中可真熱鬧,春花似錦礁鲁、人聲如沸盐欺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽冗美。三九已至,卻和暖如春着憨,著一層夾襖步出監(jiān)牢的瞬間墩衙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工甲抖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留漆改,地道東北人。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓准谚,卻偏偏與公主長得像挫剑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子柱衔,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 推薦樊破,關(guān)注 一愉棱、必備概念 1. 基本概念 一種以圖形展現(xiàn)的方式把數(shù)據(jù)從一個app移動或拷貝到另一個app(僅限iP...
    天馬行猿閱讀 2,498評論 0 4
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,182評論 25 707
  • WebSocket-Swift Starscream的使用 WebSocket 是 HTML5 一種新的協(xié)議。它實...
    香橙柚子閱讀 23,878評論 8 183
  • Ykeykey閱讀 348評論 2 5
  • 我逐漸覺得朋其,小朋友害怕一切發(fā)出機械嗡嗡聲的東西。電扇脆炎、吹風(fēng)梅猿、理發(fā)器。 她也特別敏感秒裕。對周遭環(huán)境的變化非常在意袱蚓。一件...
    有魚閱讀 216評論 0 1