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

十、交互预览类UITargetedDragPreview


   UITargetedDragPreview专门用来处理拖放交互过程中的动画与预览视图。方法解析如下:


//创建一个预览对象

/*

view:要创建的预览视图 需要注意,这个视图必须在window上

param:配置参数

target:容器视图,用来展示预览,一般设置为view的父视图

*/

- (instancetype)initWithView:(UIView *)view parameters:(UIDragPreviewParameters *)parameters target:(UIDragPreviewTarget *)target;

//同上

-(instancetype)initWithView:(UIView *)view parameters:(UIDragPreviewParameters *)parameters;

//同上

- (instancetype)initWithView:(UIView *)view;

//动画承载者

@property (nonatomic, readonly) UIDragPreviewTarget* target;

//动画视图

@property (nonatomic, readonly) UIView *view;

//配置参数

@property (nonatomic, readonly, copy) UIDragPreviewParameters *parameters;

//尺寸

@property (nonatomic, readonly) CGSize size;

//返回新的对象

- (UITargetedDragPreview *)retargetedPreviewWithTarget:(UIDragPreviewTarget *)newTarget;

UIDragPreviewTarget主要用来设置动画的起始视图与结束时回归的视图,其中属性方法如下:


/*

初始化方法

container:必须是在window上的view

center:动画起点与终点

transform:进行变换

*/

- (instancetype)initWithContainer:(UIView *)container center:(CGPoint)center transform:(CGAffineTransform)transform;

//同上

- (instancetype)initWithContainer:(UIView *)container center:(CGPoint)center;

//对应属性

@property (nonatomic, readonly) UIView *container;

@property (nonatomic, readonly) CGPoint center;

@property (nonatomic, readonly) CGAffineTransform transform;

UIDragPreviewParameters用来进行拖拽动画的配置,解析如下:


//构造方法并设置路径矩形

- (instancetype)initWithTextLineRects:(NSArray<NSValue /* CGRect */ *> *)textLineRects;

//显示的路径

@property (nonatomic, copy, nullable) UIBezierPath *visiblePath;

//背景色

@property (nonatomic, copy, null_resettable) UIColor *backgroundColor;

我们可以使用任意自定义的视图来展现这个预览动画,如下图所示:


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


十一、使用拖拽操作进行自定义数据的传递


   本篇文章到这里,其实基本的内容都已经说完了,虽然比较详细,也可能难免冗余,如果你耐着性子看到了这里,那么我首先钦佩你的毅力并且感谢你的耐心。其实,拖拽交互如果进行只能对系统的提供的数据类型进行操作则应用就局限太多。试想一下,如果我们可以通过拖拽商品来进行购买,拖拽联系人来进行发送,或者在游戏中,拖拽进行卡片的融合,装备的提炼等等这种交互操作是不是会很畅快。最后,我们就来看看如何让自定义的数据类型支持拖拽操作。


   首先你需要关注两个协议,NSItemProviderWriting与NSItemProviderReading。Writing协议用来让数据支持提供给数据源,Reading协议让数据支持从数据源读出,用自定义的Person类为例:


#import <Foundation/Foundation.h>

//遵守协议

@interface Person : NSObject<NSItemProviderWriting,NSItemProviderReading>

//自定义内容

@property(nonatomic,strong)NSString * name;


@property(nonatomic,assign)NSUInteger age;


@end


//.m文件

@implementation Person

//数据归档

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

}

//提供一个标识符

+(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"];

}


//这两个是读协议

+(NSArray<NSString *> *)readableTypeIdentifiersForItemProvider{

   return @[@"object"];

}

//解归档返回

+ (nullable instancetype)objectWithItemProviderData:(NSData *)data

                                    typeIdentifier:(NSString *)typeIdentifier

                                             error:(NSError **)outError{

   Person * p = [NSKeyedUnarchiver unarchiveObjectWithData:data];

   return p;

}


@end

需要注意,在拖放行为读取数据时的类型要对应,如下:


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

   }];

}

写了这么多,难免有疏漏与错误,欢迎指导交流

上一篇:蚂蚁云原生应用运行时的探索和实践 - ArchSummit 上海


下一篇:PostgreSQL 谁堵塞了谁(锁等待检测)- pg_blocking_pids