天天看點

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;

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;

繼續閱讀