该类用于在视图类别加载图像完成后提供过渡动画。

  1. UIVit + WebCache.h 中的 sd_imageTransition
    用于UIKit(iOS和tvOS),使用
    + [UIView transitionWithView:duration:options:animations:completion] 进行过渡动画。

  2. 对于AppKit(macOS)
    使用 + [NSAnimationContext runAnimationGroup:completionHandler:]进行过渡动画。 我们可以调用+ [NSAnimationContext currentContext]来获取动画块中的上下文。 提供这些转换以用于基本用途。

  1. 如果需要复杂的动画,可以考虑直接使用Core Animation或使用SDWebImageAvoidAutoSetImage并实现自己的后映像加载完成。

动画选项

分两种情况,如果是 SD_UIKIT 类型,就直接使用系统的动画选项,否则定义的枚举类型只有一种隐式动画

1
2
3
4
5
6
7
#if SD_UIKIT
typedef UIViewAnimationOptions SDWebImageAnimationOptions;
#else
typedef NS_OPTIONS(NSUInteger, SDWebImageAnimationOptions) {
SDWebImageAnimationOptionAllowsImplicitAnimation = 1 << 0, // specify `allowsImplicitAnimation` for the `NSAnimationContext`
};
#endif

三个block代码块

1
2
3
4
5
6
7
8
//用于动画开始之前要执行的代码块
typedef void (^SDWebImageTransitionPreparesBlock)(__kindof UIView * _Nonnull view, UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL);

//用于控制展示动画的代码块
typedef void (^SDWebImageTransitionAnimationsBlock)(__kindof UIView * _Nonnull view, UIImage * _Nullable image);

//用于动画结束后要执行的代码块
typedef void (^SDWebImageTransitionCompletionBlock)(BOOL finished);

属性声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//默认情况下,我们将图像设置为动画开头的视图。 您可以禁用此功能并提供自定义设置图像处理
@property (nonatomic, assign) BOOL avoidAutoSetImage;

//过渡动画的持续时间,以秒为单位。 默认为0.5。
@property (nonatomic, assign) NSTimeInterval duration;

//用于此过渡动画(macOS)中所有动画的计时功能。
@property (nonatomic, strong, nullable) CAMediaTimingFunction *timingFunction NS_AVAILABLE_MAC(10_7);

//一个动画选项
@property (nonatomic, assign) SDWebImageAnimationOptions animationOptions;

//动画开始前所要执行的代码块
@property (nonatomic, copy, nullable) SDWebImageTransitionPreparesBlock prepares;

动画代码块
@property (nonatomic, copy, nullable) SDWebImageTransitionAnimationsBlock animations;

//动画结束时要执行的代码块。
@property (nonatomic, copy, nullable) SDWebImageTransitionCompletionBlock completion;

Conveniences分类

创建过渡的便捷方式 如果需要,请记住指定持续时间。 对于UIKit,这些转换只使用对应的animationOptions。 默认情况下,我们启用UIViewAnimationOptionAllowUserInteraction以允许用户在转换期间进行交互。 对于AppKit,这些过渡在“动画”中使用了Core Animation。 因此,您的视图必须是图层支持的。 在应用之前设置wantsLayer = YES

公共属性和方法

调用不同的类属性获取不同的动画效果,如果类属性不可用,就调用类方法类获取不同的动画效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#if __has_feature(objc_class_property)
/// 淡出过渡。
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *fadeTransition;
/// 从左转换翻转。
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *flipFromLeftTransition;
/// 从右转换翻转。
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *flipFromRightTransition;
/// 从顶部过渡翻转。
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *flipFromTopTransition;
/// 从底部过渡翻转。
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *flipFromBottomTransition;
/// 卷起过渡。
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *curlUpTransition;
/// 向下弯曲过渡。
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *curlDownTransition;
#else

+ (nonnull instancetype)fadeTransition;
+ (nonnull instancetype)flipFromLeftTransition;
+ (nonnull instancetype)flipFromRightTransition;
+ (nonnull instancetype)flipFromTopTransition;
+ (nonnull instancetype)flipFromBottomTransition;
+ (nonnull instancetype)curlUpTransition;
+ (nonnull instancetype)curlDownTransition;
#endif

方法实现

SDWebImageTransition 只有一个初始化方法,设置了动画时间为0.5秒

1
2
3
4
5
6
7
8
9
10
11
@implementation SDWebImageTransition

- (instancetype)init {
self = [super init];
if (self) {
self.duration = 0.5;
}
return self;
}

@end

SDWebImageTransition 分类中创建了不同的动画,这里区别了SD_UIKIT 和 其他。(即iOS 、tvOS、部分watchOS )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
+ (SDWebImageTransition *)fadeTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionAllowUserInteraction;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionFade;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}

+ (SDWebImageTransition *)flipFromLeftTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionFlipFromLeft | UIViewAnimationOptionAllowUserInteraction;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionPush;
trans.subtype = kCATransitionFromLeft;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}

+ (SDWebImageTransition *)flipFromRightTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionFlipFromRight | UIViewAnimationOptionAllowUserInteraction;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionPush;
trans.subtype = kCATransitionFromRight;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}

+ (SDWebImageTransition *)flipFromTopTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionFlipFromTop | UIViewAnimationOptionAllowUserInteraction;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionPush;
trans.subtype = kCATransitionFromTop;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}

+ (SDWebImageTransition *)flipFromBottomTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionFlipFromBottom | UIViewAnimationOptionAllowUserInteraction;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionPush;
trans.subtype = kCATransitionFromBottom;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}

+ (SDWebImageTransition *)curlUpTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionCurlUp | UIViewAnimationOptionAllowUserInteraction;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionReveal;
trans.subtype = kCATransitionFromTop;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}

+ (SDWebImageTransition *)curlDownTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionCurlDown | UIViewAnimationOptionAllowUserInteraction;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionReveal;
trans.subtype = kCATransitionFromBottom;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}