【问题标题】:CAShapeLayer path animation stutters while UIImageView is movingUIImageView 移动时 CAShapeLayer 路径动画卡顿
【发布时间】:2013-06-02 00:46:12
【问题描述】:

我遇到了一个我似乎无法弄清楚的问题。在我的应用程序中,我使用自定义 UIImageView 类来表示可移动对象。有些加载了静态 .png 图像并使用帧动画,而其他加载了来自 .svg 文件的 CAShapeLayer 路径。对于其中一些,当图层从一条路径动画到另一条路径时,当 UIImageView 正在移动时,我会感到口吃。

您可以在链接的视频中看到它。当我触摸美人鱼角时,会产生一个音符(svg 路径)并动画成一条鱼(另一个 svg 路径),同时向上漂移。口吃发生在动画/漂移期间。最明显的是我第三次生成鱼,大约在视频 19 秒后。 (每个动画结尾的跳跃我需要单独修复所以不用担心)

http://www.youtube.com/watch?v=lnrNWuvqQ4w

当我在 iOS 模拟器中测试应用程序时,这不会发生 - 一切都很顺利。在我的 iPad 2 上,它结结巴巴。当我关闭音符/鱼的运动(向上漂移)时,它在 iPad 上的动画很流畅,所以显然它与同时移动视图有关。我缺少一些东西,但我无法弄清楚。

这是我设置动画的方式。 PocketSVG 是我在 Github 上找到的一个类,它可以将 .svg 转换为 Bezier 路径。

animShape = [CAShapeLayer layer];
[animShape setShouldRasterize:YES];
[animShape setRasterizationScale:[[UIScreen mainScreen] scale]];

PocketSVG *tSVG;
UIBezierPath *tBezier;

PocketSVG *tSVG2;
UIBezierPath *tBezier2;
CAShapeLayer *tLayer2;
CABasicAnimation *animBezier;
CABasicAnimation *animScale;

tSVG = [[PocketSVG alloc] initFromSVGFileNamed:[NSString stringWithFormat:@"%@", tName]];

// Use PocketSVG to convert the SVG to a Bezier Path
tBezier = tSVG.bezier;
animShape.path = tBezier.CGPath;
animShape.lineWidth = 1;
animShape.strokeColor = [[UIColor blackColor] CGColor];
animShape.fillColor = [[UIColor blackColor] CGColor];
animShape.fillRule = kCAFillRuleNonZero;

// Set the frame & bounds to position the piece and set anchor point for rotation
// parentPaper is the Mermaid the note spawns from
CGPoint newCenter;
CGFloat imageScale = fabsf(parentPaper.transform.a);
newCenter = // Code excised, set center based on custom spawn points in relation to parent position and scale

animShape.bounds = CGPathGetBoundingBox(animShape.path);

CGRect lBounds = CGRectMake(newCenter.x, newCenter.y, animShape.bounds.size.width, animShape.bounds.size.height);
[animShape setFrame:lBounds];

halfSize = CGPointMake(animShape.bounds.size.width/2, animShape.bounds.size.height/2);
animShape.anchorPoint = CGPointMake(prp.childSpawnX, prp.childSpawnY);

// Create the end path for animation
tSVG2 = [[PocketSVG alloc] initFromSVGFileNamed:[NSString stringWithFormat:@"%@2", tName]];
tBezier2 = tSVG2.bezier;
tLayer2 = [CAShapeLayer layer];
tLayer2.path = tBezier2.CGPath;

// Create the animation and add it to the layer
animBezier = [CABasicAnimation animationWithKeyPath:@"path"];
animBezier.delegate = self;
animBezier.duration = prp.frameDur;
animBezier.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animBezier.fillMode = kCAFillModeForwards;
animBezier.removedOnCompletion = NO;
animBezier.autoreverses = behavior.autoReverse;

if (prp.animID < 0)  {
    animBezier.repeatCount = FLT_MAX;
}
else {
    animBezier.repeatCount = prp.animID;
}

animBezier.fromValue = (id)animShape.path;
animBezier.toValue = (id)tLayer2.path;
[animShape addAnimation:animBezier forKey:@"animatePath"];

// also scale the animation if spawned from a parent
//   i.e. small note to normal-sized fish
if (parentPaper != nil) {

    animScale = [CABasicAnimation animationWithKeyPath:@"transform"];
    animScale.delegate = self;
    animScale.duration = prp.frameDur;
    animScale.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    animScale.fillMode = kCAFillModeForwards;
    animScale.removedOnCompletion = YES;
    animScale.autoreverses = NO;
    animScale.repeatCount = 1;
    animScale.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(imageScale, imageScale, 0.0)];
    animScale.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0, 1.0, 0.0)];
    [animShape addAnimation:animScale forKey:@"animateScale"];
}

[self.layer addSublayer:animShape];

这基本上就是我移动 UIImageView 的方式。我在 60 帧时使用 CADisplayLink,根据animShape.position 的现有位置找出新位置,然后像这样更新,其中self 是 UIImageView:

[self.animShape setPosition:paperCenter];

其他一切都运行顺利,只是这一组对象在 iPad 本身上运行时结结巴巴地跳来跳去。关于我做错了什么的任何想法?也许是用错误的方式移动它?我仍然对层、帧和边界感到困惑。

【问题讨论】:

    标签: ios animation svg cabasicanimation cashapelayer


    【解决方案1】:

    为了解决这个问题,我最终改变了 UIImageView 的移动方式。我没有通过我的游戏循环更改帧位置,而是将其切换到该位置的 CAKeyframeAnimation,因为它是一个只运行一次的临时运动。我使用CGPathAddCurveToPoint 来复制我最初拥有的正弦波运动。这很简单,我可能一开始就应该这样做。

    我只能推测卡顿是由于将其移动通过 CADisplayLink 循环,而它的动画是分开的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多