一、引言
在使用PC进行操作时,你一定遇到过这样的场景,可以将图片直接拖入聊天软件进行发送,可以将文档、音乐、视频文件等文件拖入相应应用程序直接进行使用。这种拖拽操作交互极大的方便了电脑的使用。在iOS11中,你可以在iPhone或iPad上构建这种交互体验!
说在前面的话:
拖拽操作在iPad上是支持跨应用程序的,你可以从一个应用中拖取项目,通过Home键回到主界面并且打开另一个应用程序,然后将被拖拽的项目传递给这个应用程序中。在iPhone上,拖拽操作只支持当前应用程序内,你可以将某个元素从一个界面拖拽到另一个,这种维度的操作可以给设计人员更大的灵活性。
拖拽操作被设计成系统管理,开发者不需要为App申请特殊的用户权限。
二、拖拽源
对于拖拽操作,至少要有两个组件,一个组件作为拖拽源用来提供数据,一个组件作为拖拽目的用来接收数据,当前,同一个组件既可以是拖拽源也可以是拖拽目的。首先我们先来看拖拽源,在UIKit框架中,iOS11默认实现了一些组件可以作为拖拽源, 例如UITextField、UITextView、UITableView和UICollectionView等。文本组件默认支持拖拽操作进行文本的传递,对于列表组件则默认支持元素的拖拽。例如,在UITextField选中的文案中进行拖拽,可以将文字拖拽出来,效果如下图:
任意的UIView组件都可以作为拖拽源,让其成为拖拽源其实也十分简单,只需要3步:
1.创建一个UIDragInteraction行为对象。
2.设置UIDragInteraction对象的代理并实现相应方法。
3.将UIDragInteraction对象添加到指定View上。
最简单的可拖拽组件的创建示例代码如下:
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.dragView];
}
//创建View
-(UIView *)dragView{
if (!_dragView) {
_dragView = [[UIView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
_dragView.backgroundColor = [UIColor redColor];
[_dragView addInteraction:self.dragInteraction];
}
return _dragView;
//创建拖拽行为对象
-(UIDragInteraction *)dragInteraction{
if (!_dragInteraction) {
_dragInteraction = [[UIDragInteraction alloc]initWithDelegate:self];
//要设置可用 注意!!!
[_dragInteraction setEnabled:YES];
return _dragInteraction;
//实现提供数据的代理方法
- (NSArray<UIDragItem *> *)dragInteraction:(UIDragInteraction *)interaction itemsForBeginningSession:(id<UIDragSession>)session{
//数据提供者
NSItemProvider * provider = [[NSItemProvider alloc]initWithObject:@"Hello World"];
UIDragItem * item = [[UIDragItem alloc]initWithItemProvider:provider];
return @[item];
上面的dragInteraction:代理方法用来提供要传递的数据,传递的数据必须遵守相应的承诺协议,后面会给大家介绍,这里只是简单返回了一个字符串数据Hello World,运行工程,你可以试验下,可以直接将我们自定义的视图拖拽进UITextField并在其中显示Hello World。
三、关于UIDragInteraction类
所有可以接收拖拽行为的组件都必须通过这个类实现,这个类中属性意义列举如下:
//初始化方法
- (instancetype)initWithDelegate:(id<UIDragInteractionDelegate>)delegate;
//代理
@property (nonatomic, nullable, readonly, weak) id<UIDragInteractionDelegate> delegate;
//是否支持多种手势都接收响应
@property (nonatomic) BOOL allowsSimultaneousRecognitionDuringLift;
//设置是否有效
@property (nonatomic, getter=isEnabled) BOOL enabled;
//获取默认是否有效 不同的设备这个值将有所区别
@property (class, nonatomic, readonly, getter=isEnabledByDefault) BOOL enabledByDefault;
四、UIDragInteractionDelegate协议
UIDragInteractionDelegate用来处理拖拽源的行为与数据。其中定义了一个必须实现的方法和许多可选实现的方法。解析如下:
/*
这个方法是必须实现的用来返回拖拽源提供的数据
需要注意,这个函数需要返回一个数组,数组中可以有多个数据源
如果返回空数组,则拖拽行为不会开始
*/
- (NSArray<UIDragItem *> *)dragInteraction:(UIDragInteraction *)interaction itemsForBeginningSession:(id<UIDragSession>)session;
这个方法用来自定义拖拽效果的预览视图 关于预览视图,后面会介绍
需要注意,系统默认会提供一个预览视图,不实现这个方法即是使用系统默认的
如果返回nil,则会去除预览动画
- (nullable UITargetedDragPreview *)dragInteraction:(UIDragInteraction *)interaction previewForLiftingItem:(UIDragItem *)item session:(id<UIDragSession>)session;
拖拽动画即将开始时会调用此函数
- (void)dragInteraction:(UIDragInteraction *)interaction willAnimateLiftWithAnimator:(id<UIDragAnimating>)animator session:(id<UIDragSession>)session;
//拖拽行为会话即将开始时调用的方法
- (void)dragInteraction:(UIDragInteraction *)interaction sessionWillBegin:(id<UIDragSession>)session;
//这个方法设置数据的防止是否允许数据的 移动操作,需要注意,这个只有在app内有效,跨app的操作会总是复制数据
- (BOOL)dragInteraction:(UIDragInteraction *)interaction sessionAllowsMoveOperation:(id<UIDragSession>)session;
//设置是否允许跨应用程序进行拖拽 ipad
- (BOOL)dragInteraction:(UIDragInteraction *)interaction sessionIsRestrictedToDraggingApplication:(id<UIDragSession>)session;
//设置预览视图是否显示原始大小
- (BOOL)dragInteraction:(UIDragInteraction *)interaction prefersFullSizePreviewsForSession:(id<UIDragSession>)session;
当拖拽源被移动时调用,可以用如下方法获取其坐标
NSLog(@"%f,%f",[session locationInView:self.view].x,[session locationInView:self.view].y);
- (void)dragInteraction:(UIDragInteraction *)interaction sessionDidMove:(id<UIDragSession>)session;
//拖拽行为将要结束时调用
- (void)dragInteraction:(UIDragInteraction *)interaction session:(id<UIDragSession>)session willEndWithOperation:(UIDropOperation)operation;
//拖拽行为已经结束时调用
- (void)dragInteraction:(UIDragInteraction *)interaction session:(id<UIDragSession>)session didEndWithOperation:(UIDropOperation)operation;
//拖拽源进行了放置操作后调用
- (void)dragInteraction:(UIDragInteraction *)interaction sessionDidTransferItems:(id<UIDragSession>)session;
//设置拖拽动作取消的视图动画 返回nil则消除动画
-(nullable UITargetedDragPreview *)dragInteraction:(UIDragInteraction *)interaction previewForCancellingItem:(UIDragItem *)item withDefault:(UITargetedDragPreview *)defaultPreview;
//拖拽动作即将取消时调用的方法
- (void)dragInteraction:(UIDragInteraction *)interaction item:(UIDragItem *)item willAnimateCancelWithAnimator:(id<UIDragAnimating>)animator;
//设置是否允许向拖拽中的项目添加数据
可以返回数据载体数组 当拖拽过程中 点击可拖拽的组件时会触发
- (NSArray<UIDragItem *> *)dragInteraction:(UIDragInteraction *)interaction itemsForAddingToSession:(id<UIDragSession>)session withTouchAtPoint:(CGPoint)point;
//设置允许进行拖拽中追加数据的拖拽行为会话
- (nullable id<UIDragSession>)dragInteraction:(UIDragInteraction *)interaction sessionForAddingItems:(NSArray<id<UIDragSession>> *)sessions withTouchAtPoint:(CGPoint)point;
//将要向拖拽组件中追加数据时调用
- (void)dragInteraction:(UIDragInteraction *)interaction session:(id<UIDragSession>)session willAddItems:(NSArray<UIDragItem *> *)items forInteraction:(UIDragInteraction *)addingInteraction;
上面列举的协议方法中有关联到其他许多iOS11中新增的类,后面会一一介绍。其实,完成了以上内容的了解,你就已经可以完全随心所欲的定制拖拽源组件了。