2

我的应用程序会拍摄一张静态照片并为嘴部区域设置动画以模拟说话。然而,大约有 1/4 的时间,一些隐藏的 calayer 会在整个动画中不断闪烁。

这是应用程序正常工作时的样子。这是应用程序出现故障时的样子。 编辑:更好的视频

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

如果它与路径无关,那么我消除的一些罪魁祸首是:

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

  • iphone vs 模拟器 - 两个设备都出现问题

  • 动画图片的数量 - 有时会在第一次尝试时发生;其他时候它会在第 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;

}
4

1 回答 1

0

只是另一种方法(不知道您是否尝试过),您可以仅使用CABasicAnimation并将您的类设置为动画委托,并且在委托方法中您可以尝试启动下一个CABasicAnimation. 如果您没有尝试过,我可以为您提供一个示例。

于 2013-05-18T18:31:34.360 回答