Skip to content

Commit 225cbb1

Browse files
committed
Using SDWebImage 5.3.0 player to implements the animation on watchOS
1 parent 43c8cb5 commit 225cbb1

File tree

1 file changed

+79
-128
lines changed

1 file changed

+79
-128
lines changed

SDWebImageSwiftUI/Classes/ObjC/SDAnimatedImageInterface.m

Lines changed: 79 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,6 @@
88

99
#import "SDAnimatedImageInterface.h"
1010
#if SD_WATCH
11-
// ImageIO.modulemap does not contains this public header
12-
#pragma clang diagnostic push
13-
#pragma clang diagnostic ignored "-Wincomplete-umbrella"
14-
#import <ImageIO/CGImageAnimation.h>
15-
#pragma clang diagnostic pop
1611

1712
#pragma mark - SPI
1813

@@ -35,6 +30,14 @@ @protocol UIViewProtocol <NSObject>
3530

3631
@end
3732

33+
@protocol UIImageViewProtocol <NSObject>
34+
35+
- (void)startAnimating;
36+
- (void)stopAnimating;
37+
@property (nonatomic, readonly, getter=isAnimating) BOOL animating;
38+
39+
@end
40+
3841
@interface WKInterfaceObject ()
3942

4043
// This is needed for dynamic created WKInterfaceObject, like `WKInterfaceMap`
@@ -44,40 +47,17 @@ - (instancetype)_initForDynamicCreationWithInterfaceProperty:(NSString *)propert
4447

4548
@end
4649

47-
@interface SDAnimatedImageStatus : NSObject
48-
49-
@property (nonatomic, assign) BOOL shouldAnimate;
50-
@property (nonatomic, assign) CGImageAnimationStatus animationStatus;
51-
52-
@end
53-
54-
@implementation SDAnimatedImageStatus
55-
56-
- (instancetype)init {
57-
self = [super init];
58-
if (self) {
59-
_animationStatus = kCGImageAnimationStatus_Uninitialized;
60-
}
61-
return self;
62-
}
63-
64-
@end
65-
6650
@interface SDAnimatedImageInterface () {
6751
UIImage *_image;
6852
}
6953

7054
@property (nonatomic, strong, readwrite) UIImage *currentFrame;
7155
@property (nonatomic, assign, readwrite) NSUInteger currentFrameIndex;
7256
@property (nonatomic, assign, readwrite) NSUInteger currentLoopCount;
73-
@property (nonatomic, assign) NSUInteger totalFrameCount;
74-
@property (nonatomic, assign) NSUInteger totalLoopCount;
75-
@property (nonatomic, strong) UIImage<SDAnimatedImage> *animatedImage;
76-
@property (nonatomic, assign) CGFloat animatedImageScale;
77-
@property (nonatomic, strong) SDAnimatedImageStatus *currentStatus;
7857
@property (nonatomic, strong) NSNumber *animationRepeatCount;
79-
@property (nonatomic, assign, getter=isAnimatedFormat) BOOL animatedFormat;
80-
@property (nonatomic, assign, getter=isAnimating) BOOL animating;
58+
@property (nonatomic, assign) BOOL shouldAnimate;
59+
@property (nonatomic,strong) SDAnimatedImagePlayer *player; // The animation player.
60+
@property (nonatomic) id<CALayerProtocol> imageViewLayer; // The actual rendering layer.
8161

8262
@end
8363

@@ -125,142 +105,113 @@ - (void)setImage:(UIImage *)image {
125105
_image = image;
126106

127107
// Stop animating
128-
[self stopBuiltInAnimation];
129-
// Reset all value
130-
[self resetAnimatedImage];
108+
self.player = nil;
109+
self.currentFrame = nil;
110+
self.currentFrameIndex = 0;
111+
self.currentLoopCount = 0;
131112

132113
[super setImage:image];
133114
if ([image.class conformsToProtocol:@protocol(SDAnimatedImage)]) {
134-
UIImage<SDAnimatedImage> *animatedImage = (UIImage<SDAnimatedImage> *)image;
135-
NSUInteger animatedImageFrameCount = animatedImage.animatedImageFrameCount;
136-
// Check the frame count
137-
if (animatedImageFrameCount <= 1) {
115+
// Create animted player
116+
self.player = [SDAnimatedImagePlayer playerWithProvider:(id<SDAnimatedImage>)image];
117+
118+
if (!self.player) {
119+
// animated player nil means the image format is not supported, or frame count <= 1
138120
return;
139121
}
140-
self.animatedImage = animatedImage;
141-
self.totalFrameCount = animatedImageFrameCount;
142-
// Get the current frame and loop count.
143-
self.totalLoopCount = self.animatedImage.animatedImageLoopCount;
144-
// Get the scale
145-
self.animatedImageScale = image.scale;
146-
147-
NSData *animatedImageData = animatedImage.animatedImageData;
148-
SDImageFormat format = [NSData sd_imageFormatForImageData:animatedImageData];
149-
if (format == SDImageFormatGIF || format == SDImageFormatPNG) {
150-
self.animatedFormat = YES;
151-
[self startBuiltInAnimation];
152-
} else {
153-
self.animatedFormat = NO;
154-
[self stopBuiltInAnimation];
122+
123+
// Custom Loop Count
124+
if (self.animationRepeatCount != nil) {
125+
self.player.totalLoopCount = self.animationRepeatCount.unsignedIntegerValue;
155126
}
127+
128+
// // RunLoop Mode
129+
// self.player.runLoopMode = self.runLoopMode;
130+
//
131+
// // Play Rate
132+
// self.player.playbackRate = self.playbackRate;
133+
134+
// Setup handler
135+
__weak typeof(self) wself = self;
136+
self.player.animationFrameHandler = ^(NSUInteger index, UIImage * frame) {
137+
__strong typeof(self) sself = wself;
138+
sself.currentFrameIndex = index;
139+
sself.currentFrame = frame;
140+
[sself displayLayer:sself.imageViewLayer];
141+
};
142+
self.player.animationLoopHandler = ^(NSUInteger loopCount) {
143+
__strong typeof(self) sself = wself;
144+
sself.currentLoopCount = loopCount;
145+
};
146+
147+
// Update should animate
148+
[self updateShouldAnimate];
149+
if (self.shouldAnimate) {
150+
[self startAnimating];
151+
}
152+
153+
[self displayLayer:self.imageViewLayer];
156154
}
157155
}
158156

159157
- (void)updateAnimation {
160158
[self updateShouldAnimate];
161-
if (self.currentStatus.shouldAnimate) {
162-
[self startBuiltInAnimation];
163-
} else {
164-
[self stopBuiltInAnimation];
165-
}
166-
}
167-
168-
- (void)startBuiltInAnimation {
169-
if (self.currentStatus && self.currentStatus.animationStatus == 0) {
170-
return;
171-
}
172-
UIImage<SDAnimatedImage> *animatedImage = self.animatedImage;
173-
NSData *animatedImageData = animatedImage.animatedImageData;
174-
NSUInteger maxLoopCount;
175-
if (self.animationRepeatCount != nil) {
176-
maxLoopCount = self.animationRepeatCount.unsignedIntegerValue;
159+
if (self.shouldAnimate) {
160+
[self startAnimating];
177161
} else {
178-
maxLoopCount = animatedImage.animatedImageLoopCount;
179-
}
180-
if (maxLoopCount == 0) {
181-
// The documentation says `kCFNumberPositiveInfinity may be used`, but it actually treat as 1 loop count
182-
// 0 was treated as 1 loop count as well, not the same as Image/IO or UIKit
183-
maxLoopCount = ((__bridge NSNumber *)kCFNumberPositiveInfinity).unsignedIntegerValue - 1;
162+
[self stopAnimating];
184163
}
185-
NSDictionary *options = @{(__bridge NSString *)kCGImageAnimationLoopCount : @(maxLoopCount)};
186-
SDAnimatedImageStatus *status = [[SDAnimatedImageStatus alloc] init];
187-
status.shouldAnimate = YES;
188-
__weak typeof(self) wself = self;
189-
status.animationStatus = CGAnimateImageDataWithBlock((__bridge CFDataRef)animatedImageData, (__bridge CFDictionaryRef)options, ^(size_t index, CGImageRef _Nonnull imageRef, bool * _Nonnull stop) {
190-
__strong typeof(wself) self = wself;
191-
if (!self) {
192-
*stop = YES;
193-
return;
194-
}
195-
if (!status.shouldAnimate) {
196-
*stop = YES;
197-
return;
198-
}
199-
// The CGImageRef provided by this API is GET only, should not call CGImageRelease
200-
self.currentFrame = [[UIImage alloc] initWithCGImage:imageRef scale:self.animatedImageScale orientation:UIImageOrientationUp];
201-
self.currentFrameIndex = index;
202-
// Render the frame
203-
[self displayLayer];
204-
});
205-
206-
self.currentStatus = status;
207164
}
208165

209-
- (void)stopBuiltInAnimation {
210-
self.currentStatus.shouldAnimate = NO;
211-
self.currentStatus.animationStatus = kCGImageAnimationStatus_Uninitialized;
212-
}
213-
214-
- (void)displayLayer {
215-
if (self.currentFrame) {
216-
id<CALayerProtocol> layer = [self _interfaceView].layer;
217-
layer.contentsScale = self.animatedImageScale;
218-
layer.contents = (__bridge id)self.currentFrame.CGImage;
166+
- (void)displayLayer:(id<CALayerProtocol>)layer {
167+
UIImage *currentFrame = self.currentFrame;
168+
if (currentFrame) {
169+
layer.contentsScale = currentFrame.scale;
170+
layer.contents = (__bridge id)currentFrame.CGImage;
219171
}
220172
}
221173

222-
- (void)resetAnimatedImage
223-
{
224-
self.animatedImage = nil;
225-
self.totalFrameCount = 0;
226-
self.totalLoopCount = 0;
227-
self.currentFrame = nil;
228-
self.currentFrameIndex = 0;
229-
self.currentLoopCount = 0;
230-
self.animatedImageScale = 1;
231-
self.animatedFormat = NO;
232-
self.currentStatus = nil;
174+
// on watchOS, it's the native imageView itself's layer
175+
- (id<CALayerProtocol>)imageViewLayer {
176+
return [[self _interfaceView] layer];
233177
}
234178

235179
- (void)updateShouldAnimate
236180
{
237181
id<UIViewProtocol> view = [self _interfaceView];
238182
BOOL isVisible = view.window && view.superview && ![view isHidden] && view.alpha > 0.0;
239-
self.currentStatus.shouldAnimate = self.isAnimating && self.animatedImage && self.isAnimatedFormat && self.totalFrameCount > 1 && isVisible;
183+
self.shouldAnimate = self.player && isVisible;
184+
}
185+
186+
- (BOOL)isAnimating
187+
{
188+
if (self.player) {
189+
return self.player.isPlaying;
190+
} else {
191+
id<UIImageViewProtocol> view = (id<UIImageViewProtocol>)[self _interfaceView];
192+
return [view isAnimating];
193+
}
240194
}
241195

242196
- (void)startAnimating {
243-
self.animating = YES;
244-
if (self.animatedImage) {
245-
[self startBuiltInAnimation];
197+
if (self.player) {
198+
[self.player startPlaying];
246199
} else if (_image.images.count > 0) {
247200
[super startAnimating];
248201
}
249202
}
250203

251204
- (void)startAnimatingWithImagesInRange:(NSRange)imageRange duration:(NSTimeInterval)duration repeatCount:(NSInteger)repeatCount {
252-
self.animating = YES;
253-
if (self.animatedImage) {
254-
[self startBuiltInAnimation];
205+
if (self.player) {
206+
[self.player startPlaying];
255207
} else if (_image.images.count > 0) {
256208
[super startAnimatingWithImagesInRange:imageRange duration:duration repeatCount:repeatCount];
257209
}
258210
}
259211

260212
- (void)stopAnimating {
261-
self.animating = NO;
262-
if (self.animatedImage) {
263-
[self stopBuiltInAnimation];
213+
if (self.player) {
214+
[self.player stopPlaying];
264215
} else if (_image.images.count > 0) {
265216
[super stopAnimating];
266217
}

0 commit comments

Comments
 (0)