私のアプリは静止写真を撮り、口の領域をアニメーション化して会話をエミュレートします。ただし、約 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;
}