I am using a UIViewPropertyAnimator
to animate the frame of a UICollectionViewCell
. I look at the velocity of a pan gesture recognizer to decide whether the animator should finish naturally or reverse and go back to the initial state.
In all simulators, on my iPhone 5s as well as 6s+, these animations run flawlessly. On my iPhone 7+, however, I am getting strange frame flickering whenever I reverse the animation. See code below for how I do this. The effect on the iPhone 7+ is that as soon as I set reversed = YES
and then call continueAnimationWithTimingParameters:durationFactor:
, the frame immediately jumps to a completely different part of the screen, and then runs the reversed animation from there. Only after the animation has finished running does the frame jump back to where it was supposed to revert back to.
I have tried to remove the use of spring timing parameters, but that did not make a difference.
This is an abstracted version of the code:
- (void)prepareAnimation {
// Called when user begins panning in certain direction
// ...
self.cardFrameAnimator = [[UIViewPropertyAnimator alloc] initWithDuration:0.5 dampingRatio:0.8 animations:^{
[self currentCell].frame = targetFrame;
}];
}
- (void)panningEndedWithTranslation:(CGPoint)translation velocity:(CGPoint)velocity
{
if (self.cardFrameAnimator.isRunning)
{
return;
}
CGFloat screenHeight = [[UIScreen mainScreen] bounds].size.height;
CGVector velocityVector = CGVectorMake(velocity.x / 500, velocity.y / 500);
__weak CardStackCollectionViewController *weakSelf = self;
switch (self.currentState) {
case CurrentStateStacked:
if (translation.y <= -screenHeight / 3 || velocity.y <= -100)
{
// Let the animation run to completion
self.cardFrameAnimator.reversed = NO;
[self setCurrentCellsCornerRadius:0];
[self.cardFrameAnimator addCompletion:^(UIViewAnimatingPosition finalPosition) {
weakSelf.activeCellState = CurrentStateFullscreen;
}];
}
else
{
// Revert the animation back to the default state
self.cardFrameAnimator.reversed = YES;
[self setCurrentCellsCornerRadius:20];
[self.cardFrameAnimator addCompletion:^(UIViewAnimatingPosition finalPosition) {
weakSelf.activeCellState = CurrentStateStacked;
}];
}
break;
case CurrentStateFullscreen:
if (translation.y >= screenHeight / 3 || velocity.y >= 100)
{
// Let the animation run to completion
self.cardFrameAnimator.reversed = NO;
[self setCurrentCellsCornerRadius:20];
[self.cardFrameAnimator addCompletion:^(UIViewAnimatingPosition finalPosition) {
weakSelf.activeCellState = CurrentStateStacked;
}];
}
else
{
// Revert the animation back to the default state
self.cardFrameAnimator.reversed = YES;
[self setCurrentCellsCornerRadius:0];
[self.cardFrameAnimator addCompletion:^(UIViewAnimatingPosition finalPosition) {
weakSelf.activeCellState = CurrentCellStateFullscreen;
}];
}
break;
}
UISpringTimingParameters *springParameters = [[UISpringTimingParameters alloc] initWithDampingRatio:0.8 initialVelocity:velocityVector];
[self.cardFrameAnimator continueAnimationWithTimingParameters:springParameters durationFactor:1.0];
}