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 "LOTAnimationCache.h"
|
||||||
#import "LOTCompositionContainer.h"
|
#import "LOTCompositionContainer.h"
|
||||||
|
|
||||||
|
static NSString * const kCompContainerAnimationKey = @"play";
|
||||||
|
|
||||||
@implementation LOTAnimationView {
|
@implementation LOTAnimationView {
|
||||||
LOTCompositionContainer *_compContainer;
|
LOTCompositionContainer *_compContainer;
|
||||||
NSNumber *_playRangeStartFrame;
|
NSNumber *_playRangeStartFrame;
|
||||||
@ -208,14 +210,32 @@
|
|||||||
if (!_sceneModel) {
|
if (!_sceneModel) {
|
||||||
return 0;
|
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 {
|
- (NSNumber *)_frameForProgress:(CGFloat)progress {
|
||||||
if (!_sceneModel) {
|
if (!_sceneModel) {
|
||||||
return @0;
|
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
|
# pragma mark - Completion Block
|
||||||
@ -293,10 +313,13 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NSNumber *currentFrame = [self _frameForProgress:_animationProgress];
|
NSNumber *currentFrame = [self _frameForProgress:_animationProgress];
|
||||||
|
|
||||||
currentFrame = @(MAX(MIN(currentFrame.floatValue, toEndFrame.floatValue), fromStartFrame.floatValue));
|
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;
|
currentFrame = fromStartFrame;
|
||||||
|
} else if (currentFrame.floatValue == fromStartFrame.floatValue && !playingForward) {
|
||||||
|
currentFrame = toEndFrame;
|
||||||
}
|
}
|
||||||
_animationProgress = [self _progressForFrame:currentFrame];
|
_animationProgress = [self _progressForFrame:currentFrame];
|
||||||
|
|
||||||
@ -313,7 +336,7 @@
|
|||||||
animation.delegate = self;
|
animation.delegate = self;
|
||||||
animation.removedOnCompletion = NO;
|
animation.removedOnCompletion = NO;
|
||||||
animation.beginTime = CACurrentMediaTime() - offset;
|
animation.beginTime = CACurrentMediaTime() - offset;
|
||||||
[_compContainer addAnimation:animation forKey:@"play"];
|
[_compContainer addAnimation:animation forKey:kCompContainerAnimationKey];
|
||||||
_isAnimationPlaying = YES;
|
_isAnimationPlaying = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,11 +397,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
-(void)setAnimationSpeed:(CGFloat)animationSpeed {
|
-(void)setAnimationSpeed:(CGFloat)animationSpeed {
|
||||||
|
BOOL directionChange = NO;
|
||||||
|
if ((animationSpeed >= 0 && _animationSpeed < 0) || (animationSpeed < 0 && _animationSpeed >= 0)) {
|
||||||
|
directionChange = YES;
|
||||||
|
}
|
||||||
_animationSpeed = animationSpeed;
|
_animationSpeed = animationSpeed;
|
||||||
|
NSNumber *frame = [_compContainer.presentationLayer.currentFrame copy];
|
||||||
if (_isAnimationPlaying && _sceneModel) {
|
if (_isAnimationPlaying && _sceneModel) {
|
||||||
NSNumber *frame = [_compContainer.presentationLayer.currentFrame copy];
|
|
||||||
[self setProgressWithFrame:frame callCompletionIfNecessary:NO];
|
[self setProgressWithFrame:frame callCompletionIfNecessary:NO];
|
||||||
[self playFromFrame:_playRangeStartFrame toFrame:_playRangeEndFrame withCompletion:self.completionBlock];
|
[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) {
|
if (!_sceneModel) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
CAAnimation *play = [_compContainer animationForKey:@"play"];
|
CAAnimation *play = [_compContainer animationForKey:kCompContainerAnimationKey];
|
||||||
if (play) {
|
if (play) {
|
||||||
return play.duration;
|
return play.duration;
|
||||||
}
|
}
|
||||||
@ -596,12 +626,14 @@
|
|||||||
# pragma mark - CAANimationDelegate
|
# pragma mark - CAANimationDelegate
|
||||||
|
|
||||||
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)complete {
|
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)complete {
|
||||||
if ([_compContainer animationForKey:@"play"] == anim &&
|
if ([_compContainer animationForKey:kCompContainerAnimationKey] == anim &&
|
||||||
[anim isKindOfClass:[CABasicAnimation class]]) {
|
[anim isKindOfClass:[CABasicAnimation class]]) {
|
||||||
CABasicAnimation *playAnimation = (CABasicAnimation *)anim;
|
CABasicAnimation *playAnimation = (CABasicAnimation *)anim;
|
||||||
NSNumber *frame = _compContainer.presentationLayer.currentFrame;
|
NSNumber *frame = _compContainer.presentationLayer.currentFrame;
|
||||||
if (complete) {
|
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 _removeCurrentAnimationIfNecessary];
|
||||||
[self setProgressWithFrame:frame callCompletionIfNecessary:NO];
|
[self setProgressWithFrame:frame callCompletionIfNecessary:NO];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user