2

私のアプリは静止写真を撮り、口の領域をアニメーション化して会話をエミュレートします。ただし、約 1/4 の確率で、非表示のキャレイヤーの一部がアニメーション全体で継続的に点滅します。

アプリが正常に動作すると、次のようになります。これは、不具合が発生したときのアプリの外観です。 編集:より良いビデオ

問題はパスに関連していると思います。アプリで、ユーザーは口の領域 (ビデオで簡単に示されています) の周りにパスを作成します。これがアニメーション化された領域になります。パスが滑らかなアニメーションになる場合もあれば、上記の不具合が発生する場合もあります。さらに、「戻る」を押してアニメーションでコントローラーをリロードしようとすると、グリッチが持続しますが、リロードする前にパスを変更すると、時々消えることがあります。

パスに関連していない場合、私が排除した原因のいくつかは次のとおりです。

  • 画像タイプ/ソース -- 画像 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 に答える