mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
iOS: Animated image should animate at the same speed regardless of framerate
Summary: In iOS 11, [CADisplayLink](https://developer.apple.com/documentation/quartzcore/cadisplaylink)'s frameInterval was deprecated in favor of preferredFramesPerSecond, but these two properties have different underlying assumptions. - set frameInterval to 2 for 30fps - set preferredFramesPerSecond to 30 for 30fps. When you use preferredFramesPerSecond, assume frameInterval is 1. This fix ensures gifs in <Image> component will animate at same speed regardless of framerate. Reviewed By: shergin Differential Revision: D21414014 fbshipit-source-id: 40ab23bab1990cf65d2802830b6835f350999537
This commit is contained in:
committed by
Facebook GitHub Bot
parent
530dffa342
commit
b0d0e51a77
@@ -181,22 +181,17 @@ static NSUInteger RCTDeviceFreeMemory() {
|
||||
{
|
||||
#if TARGET_OS_UIKITFORMAC
|
||||
// TODO: `displayLink.frameInterval` is not available on UIKitForMac
|
||||
NSTimeInterval duration = displayLink.duration;
|
||||
NSTimeInterval durationToNextRefresh = displayLink.duration;
|
||||
#else
|
||||
NSTimeInterval duration = displayLink.duration;
|
||||
// displaylink.duration -- time interval between frames, assuming maximumFramesPerSecond
|
||||
// displayLink.preferredFramesPerSecond (>= iOS 10) -- Set to 30 for displayDidRefresh to be called at 30 fps
|
||||
// displayLink.frameInterval (< iOS 10) -- # of frames that must pass before each displayDidRefresh. After iOS 10, when this is set to 2, preferredFramesPerSecond becomes 30 fps.
|
||||
// durationToNextRefresh -- Time interval to the next time displayDidRefresh is called
|
||||
NSTimeInterval durationToNextRefresh;
|
||||
if (@available(iOS 10.0, *)) {
|
||||
// Per https://developer.apple.com/documentation/quartzcore/cadisplaylink
|
||||
// displayLink.duration provides the amount of time between frames at the maximumFramesPerSecond
|
||||
// Thus we need to calculate true duration based on preferredFramesPerSecond
|
||||
if (displayLink.preferredFramesPerSecond != 0) {
|
||||
double maxFrameRate = 60.0; // default to 60 fps
|
||||
if (@available(iOS 10.3, tvOS 10.3, *)) {
|
||||
maxFrameRate = self.window.screen.maximumFramesPerSecond;
|
||||
}
|
||||
duration = duration * displayLink.preferredFramesPerSecond / maxFrameRate;
|
||||
} // else respect maximumFramesPerSecond
|
||||
} else { // version < (ios 10)
|
||||
duration = duration * displayLink.frameInterval;
|
||||
durationToNextRefresh = displayLink.targetTimestamp - displayLink.timestamp;
|
||||
} else {
|
||||
durationToNextRefresh = displayLink.duration * displayLink.frameInterval;
|
||||
}
|
||||
#endif
|
||||
NSUInteger totalFrameCount = self.totalFrameCount;
|
||||
@@ -206,13 +201,14 @@ static NSUInteger RCTDeviceFreeMemory() {
|
||||
// Check if we have the frame buffer firstly to improve performance
|
||||
if (!self.bufferMiss) {
|
||||
// Then check if timestamp is reached
|
||||
self.currentTime += duration;
|
||||
self.currentTime += durationToNextRefresh;
|
||||
NSTimeInterval currentDuration = [self.animatedImage animatedImageDurationAtIndex:currentFrameIndex];
|
||||
if (self.currentTime < currentDuration) {
|
||||
// Current frame timestamp not reached, return
|
||||
return;
|
||||
}
|
||||
self.currentTime -= currentDuration;
|
||||
// nextDuration - duration to wait before displaying next image
|
||||
NSTimeInterval nextDuration = [self.animatedImage animatedImageDurationAtIndex:nextFrameIndex];
|
||||
if (self.currentTime > nextDuration) {
|
||||
// Do not skip frame
|
||||
|
||||
Reference in New Issue
Block a user