Анимация пути CAShapeLayer заикается во время движения UIImageView

У меня возникла проблема, которую я не могу понять. В своем приложении я использую собственный класс UIImageView для представления подвижных объектов. Некоторые загружаются со статическими изображениями .png и используют покадровую анимацию, в то время как другие загружаются с путями CAShapeLayer из файлов .svg. Для некоторых из них я заикаюсь, когда слой анимируется с одного пути на другой, а UIImageView перемещается.

Вы можете увидеть это на видео по ссылке. Когда я касаюсь рога русалки, появляется записка (путь svg) и превращается в рыбу (еще один путь svg), при этом все время дрейфуя вверх. Во время этой анимации / дрейфа происходит заикание. Это наиболее заметно в третий раз, когда я нерестил рыбу, примерно через 19 секунд после начала видео. (Прыжки в конце каждой анимации мне нужно исправить отдельно, так что не беспокойтесь об этом)

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

Этого не происходит, когда я тестирую приложение в iOS Simulator - все гладко. На моем iPad 2 он заикается. Когда я выключаю движение ноты / рыбы (дрейф вверх), анимация на iPad плавная, поэтому очевидно, что это связано с одновременным перемещением обзора. Я кое-что упустил, но не могу понять.

Вот как я настроил анимацию. PocketSVG - это класс, который я нашел на Github, который преобразует .svg в путь Безье.

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. Я использую CADisplayLink на 60 кадрах, определяю новое место на основе существующей позиции animShape.position и обновляю его следующим образом, где self - это UIImageView:

[self.animShape setPosition:paperCenter];

Все остальное работает гладко, это только один набор объектов, которые заикаются и прыгают при работе на самом iPad. Есть идеи, что я делаю неправильно? Может быть, двигает не туда? Я до сих пор путаюсь со слоями, рамками и границами.


person BTGunner    schedule 23.05.2013    source источник


Ответы (1)


Чтобы исправить это, я изменил способ перемещения UIImageView. Вместо того, чтобы изменять положение кадра в моем игровом цикле, я переключил его на CAKeyframeAnimation в позиции, поскольку это временное движение, которое выполняется только один раз. Я использовал CGPathAddCurveToPoint, чтобы воспроизвести движение синусоидальной волны, которое у меня было изначально. Это было довольно просто, и я, наверное, должен был сделать это с самого начала.

Я могу только предположить, что заикание было вызвано перемещением его через цикл CADisplayLink при отдельной анимации.

person BTGunner    schedule 01.06.2013