iOS 11 Drag Drop使用(一)

章节

Drag & Drop除了基础APIs外,还为tableView,collectionView、textView提供了高级APIs,所以本系列分为以下几个部分:

概述

Drag & Drop是iOS 11中新增的API,允许App内或不同App之间通过手势Drag(拖拽)、Drop(投放)来交换数据。


1-1

由于iPad的分屏多任务支持,可以使用Drag、Drop的全部特性,iPhone只能在App内部使用。

API结构

Drag、Drop

基础部分:

  • UIDragInteraction、UIDropInteraction
  • UIDragSession、UIDropSession
  • UIDragPreview、UIDragPreviewParameters
  • UIDragItem、NSItemProvider

tableView:

  • UITableViewDragDelegate, UITableViewDropDelegate, UITableViewDropCoordinator, UITableViewDropItem, UITableViewDropPlaceholderContext

collectionView:

  • UICollectionViewDragDelegate, UICollectionViewDropDelegate, UICollectionViewDropCoordinator, UICollectionViewDropItem, UICollectionViewDropPlaceholderContext

示例

本篇将通过一个demo App与系统的照片App之间通过Drag、Drop来传递图片,解释部分基础API的使用。

  1. 首先,新建一个Xcode project,在ViewController中添加一个UIimageview,设置一个初始image。

2. 实现Drag功能
为了能够将UIimageview中的image拖拽到相册中,需要实现Drag功能,能够响应Drag手势。

2.1 确定Drag目标,本Demo中使用UIimageview。使用UIDragInteraction来实现,在viewDidLoad中添加

[self customEnableDraggingOnView:self.imageView dragInteractionDelegate:self];
/**
 add dragging support for specify view
 */
- (void)customEnableDraggingOnView:(UIView*)view dragInteractionDelegate:(id<UIDragInteractionDelegate>)delegate {
    if (!view) {
        return;
    }
    
    UIDragInteraction *dragInteraction = [[UIDragInteraction alloc] initWithDelegate:delegate];
    [view addInteraction:dragInteraction];
}

2.2 添加interaction后,当系统识别到针对imageView的Drag手势后,会调用UIDragInteractionDelegate的方法:

/*
* 需要在此回调中提供拖拽的数据封装,因为虽然拖拽的是imageView,但是实际上需要传递的数据应该为imageView中的image。
*/
- (NSArray<UIDragItem *> *)dragInteraction:(UIDragInteraction *)interaction itemsForBeginningSession:(id<UIDragSession>)session {
    if (self.imageView.image == nil) {
        return nil;
    }
    
    /*
     * item provider为Drag、Drop之间传输数据
     * Drag、Drop支持的数据类型:
        CNContact
        CNMutableContact
        CSLocalizedString
        MKMapItem
        NSAttributedString
        NSMutableString
        NSString
        NSTextStorage
        NSURL
        UIColor
        UIImage
     */
    NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithObject:self.imageView.image];
    UIDragItem *item = [[UIDragItem alloc] initWithItemProvider:itemProvider];
    
    return @[item];
}

2.3 在Drag开始后,如图1-1所示,手指处会显示preview预览效果,默认preview视图为Drag目标本身,本例中为imageView。如果需要自定义preview,则需要实现代理方法- (nullable UITargetedDragPreview *)dragInteraction:(UIDragInteraction *)interaction previewForLiftingItem:(UIDragItem *)item session:(id<UIDragSession>)session,那什么时候需要自定义preview呢?举个栗子,假如2.1中将Drag interaction添加到self.view上,那么默认Drag preview就是self.view,显然这并不符合要求,就需要将preview改成self.imageView。

- (nullable UITargetedDragPreview *)dragInteraction:(UIDragInteraction *)interaction previewForLiftingItem:(UIDragItem *)item session:(id<UIDragSession>)session {
    UIDragPreviewParameters *pama = [[UIDragPreviewParameters alloc] init];
    pama.visiblePath = [UIBezierPath bezierPathWithRect:self.imageView.frame];
    pama.backgroundColor = [UIColor redColor];
    UITargetedDragPreview *preview = [[UITargetedDragPreview alloc] initWithView:self.otherImageView parameters:pama];
    return preview;
    
//    return nil;
}

此处,已经实现了Drag,iPad模拟器运行,将demo与照片App分屏,按住imageView Drag到照片App里,松手Drop,可以发现imageView的image就保持到照片App里了。

3. 实现Drop功能
为了能够接受从其他App Drag到本App里的数据,需要使用Drop API。
3.1 确定接收数据的目标,本例为2.1中添加的imageView

[self customEnableDroppingOnView:self.imageView dragInteractionDelegate:self];
/**
 add dropping support for specify view
 */
- (void)customEnableDroppingOnView:(UIView*)view dragInteractionDelegate:(id<UIDropInteractionDelegate>)delegate {
    if (!view) {
        return;
    }
    
    UIDropInteraction *dropInteraction = [[UIDropInteraction alloc] initWithDelegate:delegate];
    [view addInteraction:dropInteraction];
}

3.2 当Drag目标到Drop interaction所附着的view坐标范围内,会调用- (BOOL)dropInteraction:(UIDropInteraction *)interaction canHandleSession:(id<UIDropSession>)session方法:

/*
 * 此方法决定是否响应Drop session
 * 本例中只接受单个的image Drop
 */
- (BOOL)dropInteraction:(UIDropInteraction *)interaction canHandleSession:(id<UIDropSession>)session {
    NSLog(@"---->>>>>>> canHandleSession");
    // only support image
    return [session hasItemsConformingToTypeIdentifiers:@[(__bridge_transfer NSString*)kUTTypeImage]] && session.items.count==1;
}

3.3 定义数据传输方式

/*
 当
 - (BOOL)dropInteraction:(UIDropInteraction *)interaction canHandleSession:(id<UIDropSession>)session
 返回YES后,就会调用此代理,
 UIDropProposal决定数据传输的方式,一般来说,
 1️⃣ 外部App drag到本App,使用copy来复制数据;
 2️⃣ App内部drag时,只移动数据
 */
- (UIDropProposal *)dropInteraction:(UIDropInteraction *)interaction sessionDidUpdate:(id<UIDropSession>)session {
    // localDragSession 不为nil时,表示App内部Drag、Drop
    if (session.localDragSession != nil) {
        //NSLog(@"---->>>>>>> UIDropOperationMove");
        return [[UIDropProposal alloc] initWithDropOperation:UIDropOperationMove];
    }
    // 外部Drag 目标
    else {
        CGPoint loc = [session locationInView:self.view];
        if (CGRectContainsPoint(self.imageView.frame, loc)) {
            //NSLog(@"---->>>>>>> UIDropOperationCopy");
            return [[UIDropProposal alloc] initWithDropOperation:UIDropOperationCopy];
        }
        else {
            return [[UIDropProposal alloc] initWithDropOperation:UIDropOperationForbidden];
        }
    }
    
    return [[UIDropProposal alloc] initWithDropOperation:UIDropOperationCancel];
}

3.4 Drop发生时

/*
 在Drop interaction的View上Drop内容时调用,具体数据的数据、UI表现在此方法中定义。
 */
- (void)dropInteraction:(UIDropInteraction *)interaction performDrop:(id<UIDropSession>)session {
    // App内Drag、Drop,只移动imageView的位置
    if (session.localDragSession != nil) {
        //self.imageView.center = [session locationInView:self.view];
    }
    else {
        // dragItem来自外部App时,需要加载具体的数据
        // 本例中即为从照片App中拷贝Drag图片到本App,然后使用imageView显示
        for (UIDragItem *item in session.items) {
            __weak __typeof(self) weakSelf = self;
            [item.itemProvider loadObjectOfClass:[UIImage class] completionHandler:^(id<NSItemProviderReading>  _Nullable object, NSError * _Nullable error) {
                if (error) {
                    NSLog(@"----->>>>>> load data err: %@", [error localizedDescription]);
                    return ;
                }
                
                if (!object) {
                    return;
                }
                
                dispatch_async(dispatch_get_main_queue(), ^{
                    __strong __typeof(self) self = weakSelf;
                    self.imageView.image = (UIImage*)object;
                });
            }];
        }
    }
}

3.5 Drop功能完成,运行App,从照片App Drag图片到imageView上,然后Drop图片,可以发现,imageView就会显示所Drag的图片了。

Next:

  • Drag and Drop with Collection and Table View

参考资料

文档

视频

代码

Tips

文章难免会有错误、理解错位的地方,请不吝指教。🙏

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,525评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,203评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,862评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,728评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,743评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,590评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,330评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,244评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,693评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,885评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,001评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,723评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,343评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,919评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,042评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,191评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,955评论 2 355

推荐阅读更多精彩内容