2009-10-19 7 views
0

J'essaye de faire quelques animations en utilisant Core Animation sur l'iphone. J'utilise CABasicAnimation sur CALayer. C'est une animation directe d'un endroit aléatoire en haut de l'écran au bas de l'écran à une vitesse aléatoire, j'ai 30 éléments qui font la même animation en continu jusqu'à ce qu'une autre action se produise. Mais la performance sur l'iPhone 3G est très lente lorsque les animations commencent. L'image est seulement 8k.Core Animation performance sur iphone

Est-ce la bonne approche? Comment devrais-je changer afin qu'il fonctionne mieux.

// image cached somewhere else. 
CGImageRef imageRef = [[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:name ofType:@"png"]] CGImage]; 

- (void)animate:(NSTimer *)timer 
{ 
    int startX   = round(radom() % 320); 
    float speed   = 1/round(random() % 100 + 2); 

    CALayer *layer  = [CALayer layer]; 
    layer.name   = @"layer"; 
    layer.contents  = imageRef; // cached image 
    layer.frame   = CGRectMake(0, 0, CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)); 

    int width   = layer.frame.size.width; 
    int height   = layer.frame.size.height; 

    layer.frame   = CGRectMake(startX, self.view.frame.origin.y, width, height); 

    [effectLayer addSublayer:layer]; 

    CGPoint start  = CGPointMake(startX, 0); 
    CGPoint end   = CGPointMake(startX, self.view.frame.size.height); 
    float repeatCount = 1e100; 

    CABasicAnimation *animation  = [CABasicAnimation animationWithKeyPath:@"position"]; 
    animation.delegate    = self; 
    animation.fromValue    = [NSValue valueWithCGPoint:start]; 
    animation.toValue    = [NSValue valueWithCGPoint:end]; 
    animation.duration    = speed; 
    animation.repeatCount   = repeatCount; 
    animation.autoreverses   = NO; 
    animation.removedOnCompletion = YES; 
    animation.fillMode    = kCAFillModeForwards; 

    [layer addAnimation:animation forKey:@"position"]; 
} 

Les animations sont déclenchées à l'aide d'un NSTimer.

animationTimer = [NSTimer timerWithTimeInterval:0.2 target:self selector:@selector(animate:) userInfo:nil repeats:YES]; 
[[NSRunLoop currentRunLoop] addTimer:animationTimer forMode:NSDefaultRunLoopMode]; 
+0

Étape 1: exécutez-le sur un iPhone 3GS. ;-) –

+0

lol. J'ai fait. et ça a bien fonctionné. – nico

+0

mais la majorité des utilisateurs d'iphone sont encore sur la 3G bien que :) – nico

Répondre

3

D'accord, deux choses ici:

Pourquoi utilisez-vous un NSTimer à feu à plusieurs reprises l'animation? Juste faire répéter les animations. S'ils ont besoin de pause et de resynchronisation, vous pouvez le faire avec une animation à clé. En programmant le tout, vous pouvez laisser le moteur de rendu fonctionner sans avoir à synchroniser fréquemment les nouvelles informations dans l'arbre de rendu.

Vous faites:

CGImageRef imageRef  = [[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:name ofType:@"png"]] CGImage]; 

pour 30 objets chacun sur une minuterie qui déclenche toutes les 0,2 secondes? Avez-vous profilé votre application? Quel pourcentage du temps est consacré au décodage d'image? Si vous passez sur à l'utilisation imageNamed: iPhone OS en cache des images aussi longtemps que il y a assez de RAM, ce qui devrait réduire votre temps de décodage:

CGImageRef imageRef = [[UIImage imageNamed:[NSString stringWithFormat:@"%@.png", name]] CGImage]; 

En outre, faire vos images ont la transparence qui doit être alpha composited? Si vous pouvez éviter l'alpha c'est une victoire énorme sur les anciens iPhones.

+0

J'utilise NSTimer pour créer 30 animations différentes avec un intervalle de 0.2. Par différent, je veux dire la position et la vitesse différentes. En fait, j'ai déjà mis en cache l'imageRef avant d'appeler animate :. Je coupe/colle le code là-dedans, mais l'image mise en cache en a aidé certains, mais l'animation est toujours très lente. Vous utilisez imageNamed, d'après ce que je comprends, utiliser imageWithContentsOfFile serait mieux, non? L'image contient de la transparence. L'image est une forme circulaire, donc pas moyen de contourner cela. – nico

+0

J'envisageais plutôt d'aller avec l'animation par images clés, cela améliorerait-il les performances? J'ai besoin de mettre l'animation en pause et de recommencer.Comment puis-je l'implémenter dans une animation par image clé avec différentes positions de début et de fin, et laisser le moteur de rendu faire le travail? – nico

+0

Eh bien, si vous êtes juste en train de donner un coup de pied de 30 animations différentes, alors le minuteur semble être le chemin à parcourir. En ce qui concerne la mise en cache, il est bon de vous entendre déjà, mais il est probablement plus difficile de donner des conseils lorsque vous avez des différences importantes entre ce que vous publiez et ce que vous faites. Compte tenu de ce que vous avez dit, je doute que le cadrage clé puisse aider autant. Un point, il y a une grande différence entre la transparence complète et l'alpha composé transparent du point de vue de la performance. Compte tenu de ce que vous avez posté, je ne sais pas s'il y a beaucoup plus de choses que n'importe qui peut dire sans vraies traces. –

1

Dans mon expérience layer.contents = imageRef; // L'image mise en cache est l'appel le plus cher de cette méthode.

À des fins de test j'utiliserais le même objet d'image sur eux tous. Le premier pourrait être lent mais le reste sera lisse. Pour autant que je sache, la raison en est qu'un objet UIImage, même lorsqu'il est créé, extrait effectivement toutes les données du fichier jusqu'à ce qu'il soit dessiné à l'écran.

Il ya plusieurs messages là-bas qui montrent que l'utilisation de nsurlconnections pour télécharger les images avec le fichier: // protocole va réellement enfiler le fichier obtenu (sans écrire de code threading) et parce que vous êtes des couches animées et non uiviews, sera vraiment asynchrone.

Questions connexes