瀏覽代碼

Merge pull request #3680 from dreampiggy/feature/wait_transition

Added `SDWebImageWaitTransition` to wait for transition finished and then callback `completedBlock`
DreamPiggy 2 年之前
父節點
當前提交
00d58fa58f
共有 2 個文件被更改,包括 44 次插入4 次删除
  1. 9 0
      SDWebImage/Core/SDWebImageDefine.h
  2. 35 4
      SDWebImage/Core/UIView+WebCache.m

+ 9 - 0
SDWebImage/Core/SDWebImageDefine.h

@@ -218,6 +218,15 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
      * @note This options is UI level options, has no usage on ImageManager or other components.
      */
     SDWebImageAvoidAutoCancelImage = 1 << 24,
+    
+    /**
+     * By defaults, for `SDWebImageTransition`, we just submit to UI transition and inmeediatelly callback the final `completedBlock` (`SDExternalCompletionBlock/SDInternalCompletionBlock`).
+     * This may cause un-wanted behavior if you do another transition inside `completedBlock`, because the previous transition is still runnning and un-cancellable, which mass-up the UI status.
+     * For this case, you can pass this option, we will delay the final callback, until your transition end. So when you inside `completedBlock`, no any transition is running on image view and safe to submit new transition.
+     * @note Currently we do not support `pausable/cancellable` transition. But possible in the future by using the https://developer.apple.com/documentation/uikit/uiviewpropertyanimator.
+     * @note If you have complicated transition animation, just use `SDWebImageManager` and do UI state management by yourself, do not use the top-level API (`sd_setImageWithURL:`)
+     */
+    SDWebImageWaitTransition = 1 << 25,
 };
 
 

+ 35 - 4
SDWebImage/Core/UIView+WebCache.m

@@ -232,11 +232,11 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL;
 #endif
             dispatch_main_async_safe(^{
 #if SD_UIKIT || SD_MAC
-                [self sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:transition cacheType:cacheType imageURL:imageURL];
+                [self sd_setImage:targetImage imageData:targetData options:options basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:transition cacheType:cacheType imageURL:imageURL callback:callCompletedBlockClosure];
 #else
                 [self sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock cacheType:cacheType imageURL:imageURL];
-#endif
                 callCompletedBlockClosure();
+#endif
             });
         }];
         [self sd_setImageLoadOperation:operation forKey:validOperationKey];
@@ -263,9 +263,10 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL;
     [self sd_cancelImageLoadOperationWithKey:self.sd_latestOperationKey];
 }
 
+// Set image logic without transition (like placeholder and watchOS)
 - (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData basedOnClassOrViaCustomSetImageBlock:(SDSetImageBlock)setImageBlock cacheType:(SDImageCacheType)cacheType imageURL:(NSURL *)imageURL {
 #if SD_UIKIT || SD_MAC
-    [self sd_setImage:image imageData:imageData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:nil cacheType:cacheType imageURL:imageURL];
+    [self sd_setImage:image imageData:imageData options:0 basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:nil cacheType:cacheType imageURL:imageURL callback:nil];
 #else
     // watchOS does not support view transition. Simplify the logic
     if (setImageBlock) {
@@ -277,8 +278,9 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL;
 #endif
 }
 
+// Set image logic with transition
 #if SD_UIKIT || SD_MAC
-- (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData basedOnClassOrViaCustomSetImageBlock:(SDSetImageBlock)setImageBlock transition:(SDWebImageTransition *)transition cacheType:(SDImageCacheType)cacheType imageURL:(NSURL *)imageURL {
+- (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData options:(SDWebImageOptions)options basedOnClassOrViaCustomSetImageBlock:(SDSetImageBlock)setImageBlock transition:(SDWebImageTransition *)transition cacheType:(SDImageCacheType)cacheType imageURL:(NSURL *)imageURL callback:(SDWebImageNoParamsBlock)callback {
     UIView *view = self;
     SDSetImageBlock finalSetImageBlock;
     if (setImageBlock) {
@@ -306,6 +308,7 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL;
     }
 #endif
     
+    BOOL waitTransition = SD_OPTIONS_CONTAINS(options, SDWebImageWaitTransition);
     if (transition) {
         NSString *originalOperationKey = view.sd_latestOperationKey;
 
@@ -336,6 +339,11 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL;
                 if (transition.completion) {
                     transition.completion(finished);
                 }
+                if (waitTransition) {
+                    if (callback) {
+                        callback();
+                    }
+                }
             }];
         }];
 #elif SD_MAC
@@ -380,12 +388,35 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL;
                 if (transition.completion) {
                     transition.completion(YES);
                 }
+                if (waitTransition) {
+                    if (callback) {
+                        callback();
+                    }
+                }
             }];
         }];
 #endif
+        if (!waitTransition) {
+            if (callback) {
+                callback();
+            }
+        }
     } else {
         if (finalSetImageBlock) {
             finalSetImageBlock(image, imageData, cacheType, imageURL);
+            // TODO, in 6.0
+            // for `waitTransition`, the `setImageBlock` will provide a extra `completionHandler` params
+            // Execute `callback` only after that completionHandler is called
+            if (waitTransition) {
+                if (callback) {
+                    callback();
+                }
+            }
+        }
+        if (!waitTransition) {
+            if (callback) {
+                callback();
+            }
         }
     }
 }