天天看點

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{

//提供一個辨別符

+(NSArray<NSString *> *)writableTypeIdentifiersForItemProvider{

   return @[@"object"];

-(NSArray<NSString *> *)writableTypeIdentifiersForItemProvider{

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

//解歸檔傳回

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

                                    typeIdentifier:(NSString *)typeIdentifier

                                             error:(NSError **)outError{

   Person * p = [NSKeyedUnarchiver unarchiveObjectWithData:data];

   return p;

需要注意,在拖放行為讀取資料時的類型要對應,如下:

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

   }];

寫了這麼多,難免有疏漏與錯誤,歡迎指導交流

繼續閱讀