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

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

问题描述

在关键帧动画的另一个测试中,我正在组合沿着bezier路径移动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. 图像最终以缩小的尺寸绘制。

  1. Original sized image is painted on the screen at the starting location.
  2. As the image moves along the path it shrinks smoothly.
  3. The fully shrunk image arrives at the end of the path.
  4. The image is then painted at its original size.
  5. The image is finally painted at its shrunken size.

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

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

编辑3月22日

我刚刚向GitHub上传了一个演示项目,该项目展示了沿着bezier路径移动物体的过程。代码可以在 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

I还在我的博客中写了在iOS中沿着bezier路径移动对象

I also wrote about it in my blog at Moving objects along a bezier path in iOS

推荐答案

使用Core为视图层设置动画可能会很棘手动画。有几件事令人困惑:

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 尽可能多的动画方法,并且只为关键帧动画引入Core Animation。在让 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 Scaling在动画结束时闪烁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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