Merge pull request #2886 from dreampiggy/feature_runloop_mac

Support the runloop mode control for macOS.  Which can be useful when user want to pause animation when drag the mouse, or presenting modal window
This commit is contained in:
DreamPiggy 2019-11-06 20:19:22 +08:00 committed by GitHub
commit 387944bbc1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 28 additions and 7 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,12 +25,13 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
#if SD_MAC
@property (nonatomic, assign) CVDisplayLinkRef displayLink;
@property (nonatomic, assign) CVTimeStamp outputTime;
@property (nonatomic, copy) NSRunLoopMode runloopMode;
#elif SD_IOS || SD_TV
@property (nonatomic, strong) CADisplayLink *displayLink;
#else
@property (nonatomic, strong) NSTimer *displayLink;
@property (nonatomic, strong) NSRunLoop *runloop;
@property (nonatomic, strong) NSRunLoopMode runloopMode;
@property (nonatomic, copy) NSRunLoopMode runloopMode;
@property (nonatomic, assign) NSTimeInterval currentFireDate;
#endif
@ -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,14 @@ 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)
NSString *runloopMode = self.runloopMode;
if (![runloopMode isEqualToString:NSRunLoopCommonModes] && ![runloopMode isEqualToString:NSRunLoop.mainRunLoop.currentMode]) {
return;
}
#endif
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[_target performSelector:_selector withObject:self];