mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-19 04:00:54 +00:00
Add better support for negative animation speeds
- The progress can be calculated basd on negative speed + The end frame would be a progress of 0 and the start frame a progress of 1 + Recalculate progress when the speed changes, otherwise a "jump" will be seen when restarting animation - The frame for the progress can be calculated using the newly inverted progress + Determine the absolute progress based on current progress and determine which frame to use based on animation speed - This fixes issues of animations playing with negative speeds "bouncing" back to their final position which was caused by the final frame being calculated based on a completed progress of 1 which then did not take into account the negative animation speed.
This commit is contained in:
parent
b795c24ad8
commit
3e0790a413
@ -14,6 +14,8 @@
|
||||
#import "LOTAnimationCache.h"
|
||||
#import "LOTCompositionContainer.h"
|
||||
|
||||
static NSString * const kCompContainerAnimationKey = @"play";
|
||||
|
||||
@implementation LOTAnimationView {
|
||||
LOTCompositionContainer *_compContainer;
|
||||
NSNumber *_playRangeStartFrame;
|
||||
@ -208,14 +210,32 @@
|
||||
if (!_sceneModel) {
|
||||
return 0;
|
||||
}
|
||||
return ((frame.floatValue - _sceneModel.startFrame.floatValue) / (_sceneModel.endFrame.floatValue - _sceneModel.startFrame.floatValue));
|
||||
CGFloat absoluteProgress = ((frame.floatValue - _sceneModel.startFrame.floatValue) / (_sceneModel.endFrame.floatValue - _sceneModel.startFrame.floatValue));
|
||||
if ([self _isPlayingForwards]) {
|
||||
return absoluteProgress;
|
||||
} else {
|
||||
// If the animation is playing backwards, the progress is inverted.
|
||||
return 1 - absoluteProgress;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSNumber *)_frameForProgress:(CGFloat)progress {
|
||||
if (!_sceneModel) {
|
||||
return @0;
|
||||
}
|
||||
return @(((_sceneModel.endFrame.floatValue - _sceneModel.startFrame.floatValue) * progress) + _sceneModel.startFrame.floatValue);
|
||||
CGFloat absoluteProgress = ((_sceneModel.endFrame.floatValue - _sceneModel.startFrame.floatValue) * progress);
|
||||
if ([self _isPlayingForwards]) {
|
||||
// If we're moving forward, then add the absolute progress to the start.
|
||||
return @(absoluteProgress + _sceneModel.startFrame.floatValue);
|
||||
} else {
|
||||
// It the animation is playing backwards, subtract the progress from the end.
|
||||
return @(_sceneModel.endFrame.floatValue - absoluteProgress);
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)_isPlayingForwards {
|
||||
// If the animation speed is negative, then we're moving backwards.
|
||||
return _animationSpeed >= 0;
|
||||
}
|
||||
|
||||
# pragma mark - Completion Block
|
||||
@ -295,8 +315,11 @@
|
||||
NSNumber *currentFrame = [self _frameForProgress:_animationProgress];
|
||||
|
||||
currentFrame = @(MAX(MIN(currentFrame.floatValue, toEndFrame.floatValue), fromStartFrame.floatValue));
|
||||
if (currentFrame.floatValue == toEndFrame.floatValue) {
|
||||
BOOL playingForward = [self _isPlayingForwards];
|
||||
if (currentFrame.floatValue == toEndFrame.floatValue && playingForward) {
|
||||
currentFrame = fromStartFrame;
|
||||
} else if (currentFrame.floatValue == fromStartFrame.floatValue && !playingForward) {
|
||||
currentFrame = toEndFrame;
|
||||
}
|
||||
_animationProgress = [self _progressForFrame:currentFrame];
|
||||
|
||||
@ -313,7 +336,7 @@
|
||||
animation.delegate = self;
|
||||
animation.removedOnCompletion = NO;
|
||||
animation.beginTime = CACurrentMediaTime() - offset;
|
||||
[_compContainer addAnimation:animation forKey:@"play"];
|
||||
[_compContainer addAnimation:animation forKey:kCompContainerAnimationKey];
|
||||
_isAnimationPlaying = YES;
|
||||
}
|
||||
|
||||
@ -374,11 +397,18 @@
|
||||
}
|
||||
|
||||
-(void)setAnimationSpeed:(CGFloat)animationSpeed {
|
||||
BOOL directionChange = NO;
|
||||
if ((animationSpeed >= 0 && _animationSpeed < 0) || (animationSpeed < 0 && _animationSpeed >= 0)) {
|
||||
directionChange = YES;
|
||||
}
|
||||
_animationSpeed = animationSpeed;
|
||||
if (_isAnimationPlaying && _sceneModel) {
|
||||
NSNumber *frame = [_compContainer.presentationLayer.currentFrame copy];
|
||||
if (_isAnimationPlaying && _sceneModel) {
|
||||
[self setProgressWithFrame:frame callCompletionIfNecessary:NO];
|
||||
[self playFromFrame:_playRangeStartFrame toFrame:_playRangeEndFrame withCompletion:self.completionBlock];
|
||||
} else if (directionChange) {
|
||||
// The progress needs to be re-calculated if the speed direction changes if the animation is not playing.
|
||||
_animationProgress = [self _progressForFrame:frame];
|
||||
}
|
||||
}
|
||||
|
||||
@ -464,7 +494,7 @@
|
||||
if (!_sceneModel) {
|
||||
return 0;
|
||||
}
|
||||
CAAnimation *play = [_compContainer animationForKey:@"play"];
|
||||
CAAnimation *play = [_compContainer animationForKey:kCompContainerAnimationKey];
|
||||
if (play) {
|
||||
return play.duration;
|
||||
}
|
||||
@ -596,12 +626,14 @@
|
||||
# pragma mark - CAANimationDelegate
|
||||
|
||||
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)complete {
|
||||
if ([_compContainer animationForKey:@"play"] == anim &&
|
||||
if ([_compContainer animationForKey:kCompContainerAnimationKey] == anim &&
|
||||
[anim isKindOfClass:[CABasicAnimation class]]) {
|
||||
CABasicAnimation *playAnimation = (CABasicAnimation *)anim;
|
||||
NSNumber *frame = _compContainer.presentationLayer.currentFrame;
|
||||
if (complete) {
|
||||
frame = (NSNumber *)playAnimation.toValue;
|
||||
// Set the final frame based on the animation to/from values. If playing forward, use the
|
||||
// toValue otherwise we want to end on the fromValue.
|
||||
frame = [self _isPlayingForwards] ? (NSNumber *)playAnimation.toValue : (NSNumber *)playAnimation.fromValue;
|
||||
}
|
||||
[self _removeCurrentAnimationIfNecessary];
|
||||
[self setProgressWithFrame:frame callCompletionIfNecessary:NO];
|
||||
|
Loading…
x
Reference in New Issue
Block a user