iOS CAKeyFrameAnimation 缩放动画结束时闪烁 [英] iOS CAKeyFrameAnimation Scaling Flickers at animation end

查看:50
本文介绍了iOS CAKeyFrameAnimation 缩放动画结束时闪烁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在另一项关键帧动画测试中,我将沿贝塞尔路径移动 UIImageView(称为 theImage)并在移动时将其放大,从而在最后生成 2 倍大的图像小路.我的初始代码中包含这些元素来启动动画:

In another test of Key Frame animation I am combining moving a UIImageView (called theImage) along a bezier path and scaling larger it as it moves, resulting in a 2x larger image at the end of the path. My initial code to do this has these elements in it to kick off the animation:

UIImageView* theImage = ....
float scaleFactor = 2.0;
....

theImage.center = destination;
theImage.transform = CGAffineTransformMakeScale(1.0,1.0);

CABasicAnimation *resizeAnimation = [CABasicAnimation animationWithKeyPath:@"bounds.size"];
[resizeAnimation setToValue:[NSValue valueWithCGSize:CGSizeMake(theImage.image.size.height*scaleFactor, theImage.image.size.width*scaleFactor)]];
resizeAnimation.fillMode = kCAFillModeBackwards;
resizeAnimation.removedOnCompletion = NO;  

CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
pathAnimation.path = [jdPath path].CGPath;
pathAnimation.fillMode = kCAFillModeBackwards;
pathAnimation.removedOnCompletion = NO;

CAAnimationGroup* group = [CAAnimationGroup animation];
group.animations = [NSArray arrayWithObjects:pathAnimation, resizeAnimation, nil];
group.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
group.removedOnCompletion = NO;
group.duration = duration;
group.delegate = self;

[theImage.layer addAnimation:group forKey:@"animateImage"];

然后,当动画完成时,我想保留更大尺寸的图像,所以我实现:

Then, when the animation completes I want to retain the image at the larger size, so I implement:

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{
   theImage.transform = CGAffineTransformMakeScale(scaleFactor,scaleFactor);
}

这一切都有效..有点.问题是在动画结束时 theImage 会短暂闪烁 - 足以让它看起来很糟糕.我猜这是动画结束时的过渡,我将变换设置为新大小.

This all works .. sort of. The problem is that at the end of the animation theImage flickers for a brief moment - just enough to make it look bad. I am guessing that this is the transition at the end of the animation where I set the transform to the new size.

在对此进行试验时,我尝试了与上述稍有不同的形式,但仍然出现相同的闪烁:

In experimenting with this I tried a slightly different form of the above, but still got the same flicker:

CAKeyframeAnimation *resizeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
NSValue* startSizeKey = [NSValue valueWithCATransform3D:CATransform3DScale (theImage.layer.transform, 1.0, 1.0, 1.0)];
NSValue* endSizeKey = [NSValue valueWithCATransform3D:CATransform3DScale (theImage.layer.transform, scaleFactor, scaleFactor, 1.0)]; 
NSArray* sizeKeys = [NSArray arrayWithObjects:startSizeKey, endSizeKey, nil];
[resizeAnimation setValues:sizeKeys];

....

theImage.transform = CGAffineTransformMakeScale(scaleFactor,scaleFactor);

但是当我以与原始大小相同的大小结束动画时,没有闪烁:

But when I ended the animation at the same size as the original, there was NO flicker:

CAKeyframeAnimation *resizeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
NSValue* startSizeKey = [NSValue valueWithCATransform3D:CATransform3DScale (theImage.layer.transform, 1.0, 1.0, 1.0)];
NSValue* middleSizeKey = [NSValue valueWithCATransform3D:CATransform3DScale (theImage.layer.transform, scaleFactor, scaleFactor, 1.0)];
NSValue* endSizeKey = [NSValue valueWithCATransform3D:CATransform3DScale (theImage.layer.transform, 1.0, 1.0, 1.0)]; 
NSArray* sizeKeys = [NSArray arrayWithObjects:startSizeKey, middleSizeKey, endSizeKey, nil];
[resizeAnimation setValues:sizeKeys];

....

theImage.transform = CGAffineTransformMakeScale(1.0,1.0);

所以我最大的问题是如何在没有闪烁的情况下为这张图片制作动画,并在动画结束时获得不同的尺寸?

3 月 2 日编辑

我最初的测试是放大图像.我只是尝试缩小它(IE scaleFactor = 0.4)并且闪烁更加明显,并且对于我所看到的更加明显.这是事件的顺序:

My initial tests were with scaling the image up. I just tried scaling it down (IE scaleFactor = 0.4) and the flickering was a lot more visible, and a lot more obvious as to what I am seeing. This was the sequence of events:

  1. 原始大小的图像会在起始位置绘制在屏幕上.
  2. 随着图像沿路径移动,它会平滑收缩.
  3. 完全缩小的图像到达路径的末端.
  4. 然后以原始大小绘制图像.
  5. 最终以缩小后的尺寸绘制图像.

所以我看到的闪烁似乎是第 4 步.

So it seems to be step 4 that is the flickering that I am seeing.

3 月 22 日编辑

我刚刚向 GitHub 上传了一个演示项目,该项目展示了对象沿贝塞尔路径的移动.代码可以在 PathMove

I have just uploaded to GitHub a demo project that shows off the moving of an object along a bezier path. The code can be found at PathMove

我也在我的博客 在 iOS 中沿贝塞尔路径移动对象

推荐答案

使用 Core Animation 为视图层设置动画可能会很棘手.有几件事让人感到困惑:

It can be tricky to animate a view's layer using Core Animation. There are several things that make it confusing:

  • 在图层上设置动画不会改变图层的属性.相反,只要应用了动画,它就会更改替换屏幕上原始模型层"的表示层"的属性.

  • Setting an animation on a layer doesn't change the layer's properties. Instead, it changes the properties of a "presentation layer" that replaces the original "model layer" on the screen as long as the animation is applied.

更改层的属性通常会为层添加一个隐式动画,其中属性名称作为动画的键.所以如果你想显式地为一个属性设置动画,你通常希望将属性设置为它的最终值,然后添加一个以属性名为键的动画,以覆盖隐式动画.

Changing a layer's property normally adds an implicit animation to the layer, with the property name as the animation's key. So if you want to explicitly animate a property, you usually want to set the property to its final value, then add an animation whose key is the property name, to override the implicit animation.

视图通常会禁用其图层上的隐式动画.它还以其他有些神秘的方式处理其层的属性.

A view normally disables implicit animations on its layer. It also mucks around with its layer's properties in other somewhat mysterious ways.

此外,令人困惑的是,您为视图的边界设置动画以将其放大,但在最后切换到缩放变换.

Also, it's confusing that you animate the view's bounds to scale it up, but then switch to a scale transformation at the end.

我认为最简单的方法是尽可能使用 UIView 动画方法,并且只为关键帧动画引入核心动画.让UIView添加自己的动画后,可以将关键帧动画添加到视图层,并且你的关键帧动画会覆盖UIView添加的动画.

I think the easiest way to do what you want is to use the UIView animation methods as much as possible, and only bring in Core Animation for the keyframe animation. You can add the keyframe animation to the view's layer after you've let UIView add its own animation, and your keyframe animation will override the animation added by UIView.

这对我有用:

- (IBAction)animate:(id)sender {
    UIImageView* theImage = self.imageView;
    CGFloat scaleFactor = 2;
    NSTimeInterval duration = 1;

    UIBezierPath *path = [self animationPathFromStartingPoint:theImage.center];
    CGPoint destination = [path currentPoint];

    [UIView animateWithDuration:duration animations:^{
        // UIView will add animations for both of these changes.
        theImage.transform = CGAffineTransformMakeScale(scaleFactor, scaleFactor);
        theImage.center = destination;

        // Prepare my own keypath animation for the layer position.
        // The layer position is the same as the view center.
        CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
        positionAnimation.path = path.CGPath;

        // Copy properties from UIView's animation.
        CAAnimation *autoAnimation = [theImage.layer animationForKey:@"position"];
        positionAnimation.duration = autoAnimation.duration;
        positionAnimation.fillMode = autoAnimation.fillMode;

        // Replace UIView's animation with my animation.
        [theImage.layer addAnimation:positionAnimation forKey:positionAnimation.keyPath];
    }];
}

这篇关于iOS CAKeyFrameAnimation 缩放动画结束时闪烁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆