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;
#if SD_UIKIT
/**
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;
#endif
@end
#endif

View File

@ -18,6 +18,7 @@
@interface SDAnimatedImageView () <CALayerDelegate> {
BOOL _initFinished; // Extra flag to mark the `commonInit` is called
NSRunLoopMode _runLoopMode;
double _playbackRate;
}
@ -149,6 +150,9 @@
self.player.totalLoopCount = self.animationRepeatCount;
}
// RunLoop Mode
self.player.runLoopMode = self.runLoopMode;
// Play Rate
self.player.playbackRate = self.playbackRate;
@ -188,12 +192,21 @@
- (void)setRunLoopMode:(NSRunLoopMode)runLoopMode
{
_runLoopMode = [runLoopMode copy];
self.player.runLoopMode = 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

View File

@ -25,6 +25,7 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
#if SD_MAC
@property (nonatomic, assign) CVDisplayLinkRef displayLink;
@property (nonatomic, assign) CVTimeStamp outputTime;
@property (nonatomic, strong) NSRunLoopMode runloopMode;
#elif SD_IOS || SD_TV
@property (nonatomic, strong) CADisplayLink *displayLink;
#else
@ -118,7 +119,7 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
return;
}
#if SD_MAC
// CVDisplayLink does not use runloop
self.runloopMode = mode;
#elif SD_IOS || SD_TV
[self.displayLink addToRunLoop:runloop forMode:mode];
#else
@ -141,7 +142,7 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
return;
}
#if SD_MAC
// CVDisplayLink does not use runloop
self.runloopMode = nil;
#elif SD_IOS || SD_TV
[self.displayLink removeFromRunLoop:runloop forMode:mode];
#else
@ -186,6 +187,13 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
}
- (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 ignored "-Warc-performSelector-leaks"
[_target performSelector:_selector withObject:self];