Mon application prend une photo fixe et anime la région buccale pour simuler la parole. Cependant, environ un quart du temps, certains des calques cachés clignotent continuellement pendant l'animation.
Voici à quoi ressemble l'application lorsqu'elle fonctionne correctement . Voici à quoi ressemble l'application lorsqu'elle glitches . EDIT : a meilleure vidéo
Je suppose que le problème est lié au chemin. Dans l'application, l'utilisateur crée un chemin autour de la région de la bouche (montrée brièvement dans la vidéo), et ce chemin sera la région animée. Parfois, le chemin donne lieu à une animation fluide, et d'autres fois, il donne lieu au problème ci-dessus. De plus, si j'appuie sur "retour" et que j'essaie de recharger le contrôleur avec l'animation, le problème persiste, alors que si je change le chemin avant de recharger, il disparaît parfois.
Si ce n'est pas lié au chemin, les coupables que j'ai éliminés sont les suivants :
-
type/source de l'image -- parfois cela fonctionnera pour l'image a mais pas pour l'image b, et d'autres fois il fonctionnera pour l'image b mais pas pour a. J'ai essayé des des images de la photothèque ainsi que des images enregistrées sur Internet.
-
iphone vs simulateur -- le problème se produit sur les deux appareils
-
nombre d'images animées -- parfois, cela se produit lors de la première essai ; d'autres fois, cela se produira au 5e ou au 6e essai.
Voici le code de la vue à animer. Je crée d'abord un calque tout noir, puis un calque avec l'image moins la région de la bouche, et enfin un calque avec seulement la région de la bouche. Je déplace ensuite la position du calque de la bouche, de sorte que le déplacement devienne noir et ressemble à une bouche ouverte.
EDIT : De même, si je supprime le trou de la bouche en retirant le masque du calque du visage, l'animation se déroule sans problème.
- (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);
Voici le code qui crée l'animation, à partir du contrôleur de vue
- (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;
}