使用CALayers的CAAnimation偶尔会创建闪烁的动画(包括视频)

时间:2013-05-15 04:22:46

标签: ios objective-c calayer caanimation

我的应用程序拍摄静态照片并动画嘴部区域来模仿说话。然而,大约1/4的时间,一些隐藏的calayer将在整个动画中不断闪现。

以下是该应用在works properly时的样子。 这是应用程序glitches时的样子。 编辑:better video

我假设问题与路径有关。在应用程序中,用户创建一个围绕嘴部区域的路径(在视频中简要显示),这将是动画区域。有时路径会产生平滑的动画,有时会导致上面的故障。此外,如果我按“后退”并尝试使用动画重新加载控制器,则故障仍然存在,而如果我在重新加载之前更改路径,它偶尔会消失。

如果它不是路径相关的,我消除的一些罪魁祸首是:

  • 图像类型/来源 - 有时它适用于图像a但不适用于图像 b,有时它适用于图像b但不适用于图像。我试过了 照片库中的图像以及从互联网上保存的图像。

  • iphone vs simulator - 两台设备都出现问题

  • 动画的图片数量 - 有时它会发生在第一个 尝试;其他时候会在第5或第6次尝试。

以下是要动画的视图中的代码。我首先创建一个全黑的图层,然后是图片减去嘴部区域的图层,最后是一个只是嘴部区域的图层。然后我移动嘴层的位置,使位移变成黑色,看起来像张开的嘴。

编辑:此外,如果我通过从面部图层中移除面具来移除口孔,则动画可以顺利运行。

- (id)initWithFrame:(CGRect)frame leftPt:(CGPoint)point0 rightPt:(CGPoint)point2 vertex1:(CGPoint)vertex1 vertex2:(CGPoint)vertex2 andPicture:(UIImage *)pic{

    self = [super initWithFrame:frame];
    if (self) {

        p0 = point0;
        p2 = point2;
        v1 = vertex1;
        v2 = vertex2;
        picture = pic;

        [self addBlackLayer];
        [self addFaceLayer];
        [self addMouthLayer];

        self.opaque = YES;
    }
    return self;
}
- (void)addBlackLayer {

    CALayer *blackLayer = [CALayer layer];
    blackLayer.frame = self.bounds;
    blackLayer.backgroundColor = [UIColor blackColor].CGColor;
    [self.layer addSublayer:blackLayer];

}
- (void)addFaceLayer {

    CALayer *faceLayer = [CALayer layer];
    faceLayer.frame = self.bounds;
    faceLayer.contents = (id)[picture CGImageWithProperOrientation];
    CAShapeLayer *faceMask = [CAShapeLayer layer];
    CGMutablePathRef fPath = CGPathCreateMutable();
    CGPathMoveToPoint(fPath, NULL, CGRectGetMinX(self.bounds), CGRectGetMinY(self.bounds));
    CGPathAddLineToPoint(fPath, NULL, CGRectGetMaxX(self.bounds), CGRectGetMinY(self.bounds));
    CGPathAddLineToPoint(fPath, NULL, CGRectGetMaxX(self.bounds), CGRectGetMaxY(self.bounds));
    CGPathAddLineToPoint(fPath, NULL, CGRectGetMinX(self.bounds), CGRectGetMaxY(self.bounds));
    CGPathAddLineToPoint(fPath, NULL, CGRectGetMinX(self.bounds), CGRectGetMinY(self.bounds));
    CGPathMoveToPoint(fPath, NULL, p0.x, p0.y);
    midpt = CGPointMake( (p2.x + p0.x)/2, (p2.y+ p0.y)/2);
    CGPoint c1 = CGPointMake(2*v1.x - midpt.x, 2*v1.y - midpt.y); //control points
    CGPoint c2 = CGPointMake(2*v2.x - midpt.x, 2*v2.y - midpt.y);

    CGPathAddQuadCurveToPoint(fPath, NULL, c1.x, c1.y, p2.x, p2.y);
    CGPathAddQuadCurveToPoint(fPath, NULL, c2.x, c2.y, p0.x, p0.y);

    faceMask.path = fPath;
    faceLayer.mask = faceMask;
    [faceMask setFillRule:kCAFillRuleEvenOdd];
    [self.layer addSublayer:faceLayer];
    CGPathRelease(fPath);

}

- (void)addMouthLayer {

    CGMutablePathRef mPath = CGPathCreateMutable();
    CGPathMoveToPoint(mPath, NULL, p0.x, p0.y);
    midpt = CGPointMake( (p2.x + p0.x)/2, (p2.y+ p0.y)/2);
    CGPoint c1 = CGPointMake(2*v1.x - midpt.x, 2*v1.y - midpt.y); //control points
    CGPoint c2 = CGPointMake(2*v2.x - midpt.x, 2*v2.y - midpt.y);

    CGPathAddQuadCurveToPoint(mPath, NULL, c1.x, c1.y, p2.x, p2.y);
    CGPathAddQuadCurveToPoint(mPath, NULL, c2.x, c2.y, p0.x, p0.y);

    self.mouthLayer = [CALayer layer];
    CAShapeLayer *mouthMask = [CAShapeLayer layer];
    self.mouthLayer.frame = self.bounds;
    self.mouthLayer.contents = (id)[picture CGImageWithProperOrientation];
    mouthMask.path = mPath;
    mouthMask.frame = mouthLayer.bounds;
    self.mouthLayer.mask = mouthMask;
    [self.layer addSublayer:mouthLayer];
    self.mouthLayer.frame = CGRectMake(mouthLayer.frame.origin.x, mouthLayer.frame.origin.y, mouthLayer.frame.size.width, mouthLayer.frame.size.height);
    CGPathRelease(mPath);

以下是从视图控制器

创建动画的代码
- (CAAnimation *)createAnimationWithRepeatCount:(int)count {

    CGPoint convertedStartingCenter = [self.view convertPoint:animatedFace.center toView:animatedFace];
    CGPoint endPt = CGPointMake(convertedStartingCenter.x, convertedStartingCenter.y + 15);

    CABasicAnimation *mouthDown = [CABasicAnimation animationWithKeyPath:@"position"];
    mouthDown.duration = ANIMATION_TIME;
    mouthDown.beginTime = 0;
    mouthDown.fromValue = [NSValue valueWithCGPoint:convertedStartingCenter];
    mouthDown.toValue = [NSValue valueWithCGPoint:endPt];

    CABasicAnimation *mouthUp = [CABasicAnimation animationWithKeyPath:@"position"];
    mouthUp.duration = ANIMATION_TIME;
    mouthUp.beginTime = ANIMATION_TIME;
    mouthUp.fromValue = [NSValue valueWithCGPoint:endPt];
    mouthUp.toValue = [NSValue valueWithCGPoint:convertedStartingCenter];

    CAAnimationGroup *totalAnimation = [CAAnimationGroup animation];
    [totalAnimation setAnimations:[NSArray arrayWithObjects:mouthDown,mouthUp, nil]];
    [totalAnimation setDuration:2*ANIMATION_TIME];
    [totalAnimation setRemovedOnCompletion:NO];
    [totalAnimation setFillMode:kCAFillModeForwards];
    totalAnimation.repeatCount = count;

    return totalAnimation;

}

1 个答案:

答案 0 :(得分:0)

只是另一种方法(不知道你是否尝试过),你只能使用CABasicAnimation并将你的类设置为动画委托,而在委托方法中你可以尝试启动下一个{{1 }}。如果你没试过,我可以为你提供一个例子。