iOS11新特性:新增拖拽交互体验(二)

五、放置目的地


   拖拽源是数据的提供者,放置目的地就是数据的接收者。前面我们也实验过,将自定义的拖拽源拖拽进UITextField后,文本框中会自动填充我们提供的文本数据。同样,对于任何自定义的UIView视图,我们也可以让其成为放置目的地,需要完成如下3步:


1.创建一个UIDropInteraction行为对象。


2.设置UIDropInteraction对象的代理并实现协议方法。


3.将其添加到自定义的视图中。


   例如,我们将自定义的UILabel组件用来显示拖拽的文案:


//添加视图

- (void)viewDidLoad {

   [super viewDidLoad];

   //有关拖拽源的代码 前面已经列举过 这里不再重复

   [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;

}

//放置目的地行为对象

-(UIDropInteraction*)dropInteraction{

   if (!_dropInteraction) {

       _dropInteraction = [[UIDropInteraction alloc]initWithDelegate:self];

   }

   return _dropInteraction;

}


//这个方法返回是否响应此放置目的地的放置请求

-(BOOL)dropInteraction:(UIDropInteraction *)interaction canHandleSession:(id<UIDropSession>)session{

   return YES;

}

//设置以何种方式响应拖放会话行为

-(UIDropProposal *)dropInteraction:(UIDropInteraction *)interaction sessionDidUpdate:(id<UIDropSession>)session{

   return [[UIDropProposal alloc]initWithDropOperation:UIDropOperationCopy];

}

//已经应用拖放行为后执行的操作

-(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拖放进了UILabel组件中。


六、关于UIDropInteraction类


   与UIDragInteraction类类似,这个类的作用是让组件有相应放置操作的能力。其中属性如下:


//初始化方法

- (instancetype)initWithDelegate:(id<UIDropInteractionDelegate>)delegate;

//代理对象

@property (nonatomic, nullable, readonly, weak) id<UIDropInteractionDelegate> delegate;

//是否允许多个交互行为

@property (nonatomic, assign) BOOL allowsSimultaneousDropSessions;

七、UIDropInteractionDelegate协议


   UIDropInteractionDelegate协议中所定义的方法全部是可选实现的,其用来处理用户放置交互行为。


//放置行为即将响应时触发的方法 返回值确定是否响应此次行为

- (BOOL)dropInteraction:(UIDropInteraction *)interaction canHandleSession:(id<UIDropSession>)session;

//当上面的协议方法返回YES时会接着调用这个函数

- (void)dropInteraction:(UIDropInteraction *)interaction sessionDidEnter:(id<UIDropSession>)session;

//将要处理数据时回调的方法

/*

当数据源数据添加时,这个方法也会被重新调用

这个函数需要返回一个处理行为方式UIDropProposal对象,这个我们后面再说

*/

- (UIDropProposal *)dropInteraction:(UIDropInteraction *)interaction sessionDidUpdate:(id<UIDropSession>)session;

//放置行为相应结束的时候会调用此方法

- (void)dropInteraction:(UIDropInteraction *)interaction sessionDidExit:(id<UIDropSession>)session;

//这个方法当用户进行放置时会调用,可以从session中获取被传递的数据

- (void)dropInteraction:(UIDropInteraction *)interaction performDrop:(id<UIDropSession>)session;

//放置动画完成后会调用这个方法

- (void)dropInteraction:(UIDropInteraction *)interaction concludeDrop:(id<UIDropSession>)session;

//整个拖放行为结束后会调用

- (void)dropInteraction:(UIDropInteraction *)interaction sessionDidEnd:(id<UIDropSession>)session;


//下面这些方法用来自定义放置动画

//设置放置预览动画

- (nullable UITargetedDragPreview *)dropInteraction:(UIDropInteraction *)interaction previewForDroppingItem:(UIDragItem *)item withDefault:(UITargetedDragPreview *)defaultPreview;

//这个函数每当有一个拖拽数据项放入时都会调用一次 可以进行动画

- (void)dropInteraction:(UIDropInteraction *)interaction item:(UIDragItem *)item willAnimateDropWithAnimator:(id<UIDragAnimating>)animator;

需要注意,UIDropProposal类用来进行处理回执,属性方法解析如下:


//初始化方法

/*

typedef NS_ENUM(NSUInteger, UIDropOperation) {

   //取消这次行为

   UIDropOperationCancel   = 0,

   //拒绝行为

   UIDropOperationForbidden = 1,

   //接收拷贝数据

   UIDropOperationCopy      = 2,

   //接收移动数据

   UIDropOperationMove      = 3,

}

*/

- (instancetype)initWithDropOperation:(UIDropOperation)operation;

//处理方式

@property (nonatomic, readonly) UIDropOperation operation;

//精准定位

@property (nonatomic, getter=isPrecise) BOOL precise;

//设置是否展示完整的预览尺寸

@property (nonatomic) BOOL prefersFullSizePreview;

八、拖拽数据载体UIDragItem类


   UIDragItem类用来承载要传递的数据。其通过NSItemProvider类来进行构建,传递的数据类型是有严格规定的,必须遵守一定的协议,系统的NSString,NSAttributeString,NSURL,UIColor和UIImage是默认支持的,你可以直接传递这些数据。


   UIDragItem中提供的属性方法:


//初始化方法

- (instancetype)initWithItemProvider:(NSItemProvider *)itemProvider;

//数据提供者实例

@property (nonatomic, readonly) __kindof NSItemProvider *itemProvider;

//用来传递一些额外的关联信息

@property (nonatomic, strong, nullable) id localObject;

//用来自定义每个item添加时的预览动画

@property (nonatomic, copy, nullable) UIDragPreview * _Nullable (^previewProvider)(void);

九、UIDropSession与UIDragSession


   在与拖拽交互相关的接口中,这两个是面向协议编程的绝佳范例,首先在UIKit框架中只定义了这两个协议,而并没有相关的实现类,在拖拽行为的相关回调接口中,很多id类型的参数都遵守了这个协议,我们无需知道是哪个类实现的,直接进行使用即可:


UIDropSession:


//继承于UIDragDropSession(提供基础数据), NSProgressReporting(提供数据读取进度)

@protocol UIDropSession <UIDragDropSession, NSProgressReporting>

//原始的dragSesstion会话  如果是跨应用的 则为nil

@property (nonatomic, readonly, nullable) id<UIDragSession> localDragSession;

//设置进度风格

/*

typedef NS_ENUM(NSUInteger, UIDropSessionProgressIndicatorStyle) {

   UIDropSessionProgressIndicatorStyleNone,       // 无

   UIDropSessionProgressIndicatorStyleDefault,    // 默认的

} API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(watchos, tvos);


*/

@property (nonatomic) UIDropSessionProgressIndicatorStyle progressIndicatorStyle;

//进行数据的加载

- (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>

//设置要传递的额外信息 只有在同个APP内可见

@property (nonatomic, strong, nullable) id localContext;


@end

UIDragDropSession:


//传递的数据数组

@property (nonatomic, readonly) NSArray<UIDragItem *> *items;

//当前操作行为的坐标

- (CGPoint)locationInView:(UIView *)view;

//此次行为是否允许移动操作

@property (nonatomic, readonly) BOOL allowsMoveOperation;

//是否支持应用程序层面的拖拽

@property (nonatomic, readonly, getter=isRestrictedToDraggingApplication) BOOL restrictedToDraggingApplication;

//验证传递的数据是否支持某个数据类型协议

- (BOOL)hasItemsConformingToTypeIdentifiers:(NSArray<NSString *> *)typeIdentifiers;

//验证传递的数据是否可以加载某个类

- (BOOL)canLoadObjectsOfClass:(Class<NSItemProviderReading>)aClass;

上一篇:如何通过C#读取PI实时数据


下一篇:谷歌与苹果之间战争升级:消息应用领域成最新战场