Support the runloop mode control for macOS. Which can be useful when user want to pause animation when drag the mouse, or open the Save/Open modal window

This commit is contained in:
DreamPiggy 2019-11-06 00:18:47 +08:00
parent 253a5eb7f2
commit 323e038aaf
3 changed files with 26 additions and 6 deletions

View File

@ -81,13 +81,12 @@
*/ */
@property (nonatomic, assign) BOOL resetFrameIndexWhenStopped; @property (nonatomic, assign) BOOL resetFrameIndexWhenStopped;
#if SD_UIKIT
/** /**
You can specify a runloop mode to let it rendering. You can specify a runloop mode to let it rendering.
Default is NSRunLoopCommonModes on multi-core iOS device, NSDefaultRunLoopMode on single-core iOS device Default is NSRunLoopCommonModes on multi-core device, NSDefaultRunLoopMode on single-core device
@note This is useful for some cases, for example, always specify NSDefaultRunLoopMode, if you want to pause the animation when user scroll (for Mac user, drag the mouse or touchpad)
*/ */
@property (nonatomic, copy, nonnull) NSRunLoopMode runLoopMode; @property (nonatomic, copy, nonnull) NSRunLoopMode runLoopMode;
#endif
@end @end
#endif #endif

View File

@ -18,6 +18,7 @@
@interface SDAnimatedImageView () <CALayerDelegate> { @interface SDAnimatedImageView () <CALayerDelegate> {
BOOL _initFinished; // Extra flag to mark the `commonInit` is called BOOL _initFinished; // Extra flag to mark the `commonInit` is called
NSRunLoopMode _runLoopMode;
double _playbackRate; double _playbackRate;
} }
@ -149,6 +150,9 @@
self.player.totalLoopCount = self.animationRepeatCount; self.player.totalLoopCount = self.animationRepeatCount;
} }
// RunLoop Mode
self.player.runLoopMode = self.runLoopMode;
// Play Rate // Play Rate
self.player.playbackRate = self.playbackRate; self.player.playbackRate = self.playbackRate;
@ -188,12 +192,21 @@
- (void)setRunLoopMode:(NSRunLoopMode)runLoopMode - (void)setRunLoopMode:(NSRunLoopMode)runLoopMode
{ {
_runLoopMode = [runLoopMode copy];
self.player.runLoopMode = runLoopMode; self.player.runLoopMode = runLoopMode;
} }
- (NSRunLoopMode)runLoopMode - (NSRunLoopMode)runLoopMode
{ {
return self.player.runLoopMode; if (!_runLoopMode) {
_runLoopMode = [[self class] defaultRunLoopMode];
}
return _runLoopMode;
}
+ (NSString *)defaultRunLoopMode {
// Key off `activeProcessorCount` (as opposed to `processorCount`) since the system could shut down cores in certain situations.
return [NSProcessInfo processInfo].activeProcessorCount > 1 ? NSRunLoopCommonModes : NSDefaultRunLoopMode;
} }
- (void)setPlaybackRate:(double)playbackRate - (void)setPlaybackRate:(double)playbackRate

View File

@ -25,6 +25,7 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
#if SD_MAC #if SD_MAC
@property (nonatomic, assign) CVDisplayLinkRef displayLink; @property (nonatomic, assign) CVDisplayLinkRef displayLink;
@property (nonatomic, assign) CVTimeStamp outputTime; @property (nonatomic, assign) CVTimeStamp outputTime;
@property (nonatomic, strong) NSRunLoopMode runloopMode;
#elif SD_IOS || SD_TV #elif SD_IOS || SD_TV
@property (nonatomic, strong) CADisplayLink *displayLink; @property (nonatomic, strong) CADisplayLink *displayLink;
#else #else
@ -118,7 +119,7 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
return; return;
} }
#if SD_MAC #if SD_MAC
// CVDisplayLink does not use runloop self.runloopMode = mode;
#elif SD_IOS || SD_TV #elif SD_IOS || SD_TV
[self.displayLink addToRunLoop:runloop forMode:mode]; [self.displayLink addToRunLoop:runloop forMode:mode];
#else #else
@ -141,7 +142,7 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
return; return;
} }
#if SD_MAC #if SD_MAC
// CVDisplayLink does not use runloop self.runloopMode = nil;
#elif SD_IOS || SD_TV #elif SD_IOS || SD_TV
[self.displayLink removeFromRunLoop:runloop forMode:mode]; [self.displayLink removeFromRunLoop:runloop forMode:mode];
#else #else
@ -186,6 +187,13 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
} }
- (void)displayLinkDidRefresh:(id)displayLink { - (void)displayLinkDidRefresh:(id)displayLink {
#if SD_MAC
// CVDisplayLink does not use runloop, but we can provide similar behavior for modes
// May use `default` runloop to avoid extra callback when in `eventTracking` (mouse drag, scroll) or `modalPanel` (modal panel)
if (self.runloopMode && self.runloopMode != NSRunLoopCommonModes && ![self.runloopMode isEqualToString:NSRunLoop.mainRunLoop.currentMode]) {
return;
}
#endif
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks" #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[_target performSelector:_selector withObject:self]; [_target performSelector:_selector withObject:self];