Mouviciel

Création d'applications pour Mac OS X

Les coulisses d'un développeur Mac

Initiation à CoreAnimation — Première partie

Publié le vendredi 17 octobre 2008, aucun commentaire

CoreAnimation est un mécanisme de Leopard qui permet de donner du mouvement aux éléments de l'interface en exploitant le plus possible le processeur graphique. Le meilleur exemple est l'animation de TimeMachine.

J'écris cet article, et d'autres qui suivront, alors que je découvre CoreAnimation. Il s'agit d'une espèce de carnet de notes sur lequel j'enregistre ce que j'apprends. En le publiant ici j'espère que d'autres partageront cette initiation à CoreAnimation en même temps que moi.

D'autres articles existent sur le sujet. Il y a d'abord la documentation d'Apple, notamment le Core Animation Programming Guide qui peut être un bon point d'entrée au reste des documents officiels. Ensuite une série de cours sur CoreAnimation existe en français chez Saint Sylvain's Ranch. Enfin, plusieurs cas d'école sont disponibles en anglais chez Theocacao en particulier NanoLife et ArtGallery.

Première figure — Mettre CoreAnimation dans une fenêtre

Interface Builder propose un certain nombre de vues spécialisées, par exemple NSOpenGLView pour l'OpenGL, QTMovieView pour une séquence QuickTime, WebView pour un navigateur web, etc. Cependant, rien n'est proposé en standard pour CoreAnimation. Heureusement, la procédure n'est pas difficile.

Pour illustrer cela, je vous propose de créer un nouveau projet d'application Cocoa dans Xcode. Nommez-le CoreAnimationTutorial. Ajoutez une classe à ce projet : Menu File—New File..., puis Objective-C class. Nommez-la AppController.m et choisissez de créer aussi AppController.h. Il s'agit du contrôleur de l'application qui sera le cadre de nos expérimentations.

Ensuite, ouvrez le fichier qui décrit l'interface graphique MainMenu.xib. Nous allons y ajouter le controleur que nous venons de créer. Si ce n'est pas déjà fait, ouvrez la palette Library (cmd-shift-L) et la palette Inspector (cmd-shift-I).

Dans la palette Library trouvez l'élément Object de classe NSObject et faites-le glisser dans la fenêtre nommée MainMenu.xib (English). Cette fenêtre contient la description complète de l'interface graphique de l'application.

Assurez-vous que l'objet que vous venez de faire glisser est sélectionné, puis dans la palette Inspector choisissez l'onglet Identity. Dans la rubrique Class Identity Choisissez la classe AppController (c'est la classe que nous avons créée).

À ce stade, les fondations de notre application sont posées. Nous pouvons commencer les spécificités de CoreAnimation.

La base de CoreAnimation est la classe CALayer qui est analogue dans son rôle et sa structure à la classe NSView : Elle permet de faire des affichages à l'écran et de définir une arborescence d'objets CALayer. Concrètement, cela signifie que nous travaillerons dans des CALayer au lieu des NSView. Il faut donc trouver un moyen de placer une CALayer dans une fenêtre.

La technique est d'associer une CALayer à une des views de la fenêtre de l'application, grâce à la méthode setLayer: de NSView. Il s'agira de la racine de l'arborescence des CALayer. Ses dimensions sont celles de la view qui l'héberge. Voici la procédure.

D'abord, il faut que l'AppController ait connaissance de la view qu'on souhaite utiliser pour CoreAnimation. Cela se fait en deux étapes, la première dans Xcode et la deuxième dans Interface Builder. Pour la première étape, ajoutez une ligne de code à AppController.h :

//
//  AppController.h
//  CoreAnimationTutorial
//
//  Created by mouviciel on 03/10/08.
//  Copyright 2008 Mouviciel. All rights reserved.
//

#import <Cocoa/Cocoa.h>


@interface AppController : NSObject {
    IBOutlet NSView * animationView;
}

@end

Pour la deuxième étape, reprenez Interface Builder, puis ctrl-clic sur l'objet appController pour faire apparaître ses interfaces. Cliquez dans le petit cercle à droite de l'outlet animationView et faites glisser la souris en maintenant le bouton enfoncé jusqu'à la contentView de la fenêtre.

Maintenant que l'AppController a connaissance de la view à utiliser pour CoreAnimation, il reste à associer à cette vue une CALayer racine. Cela se passe dans Xcode : un framework à ajouter au projet et une méthode à ajouter à AppController.m. CoreAnimation est disponible via le framework QuartzCore. Il suffit de l'ajouter aux Frameworks déjà dans le projet (normalement, il y a seulement Cocoa dans Frameworks/Linked Frameworks). Pour cela, faites ctrl-clic sur Frameworks/Linked Frameworks puis choisissez dans le menu qui s'affiche Add—Existing Frameworks.... La fenêtre qui s'affiche vous propose de choisir dans le dossier Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks. Dans la liste, choisissez QuartzCore.framework.

Cela fait, vous pouvez modifier AppController.m de la façon suivante :

//
//  AppController.m
//  CoreAnimationTutorial
//
//  Created by mouviciel on 03/10/08.
//  Copyright 2008 Mouviciel. All rights reserved.
//

#import <QuartzCore/QuartzCore.h>
#import "AppController.h"


@implementation AppController

-(void)awakeFromNib
{
    // Ajout et activation d'une CALayer
    [animationView setLayer:[CALayer layer]];
    [animationView setWantsLayer:YES];
}

@end

Voilà, votre fenêtre est prête à recevoir des animations ! Pour l'instant ce n'est pas vraiment spectaculaire, mais la suite vous montre ce qu'on peut faire à partir de ça.

Deuxième figure — Afficher une image dans une CALayer

Dans son Core Animation Programming Guide, Apple indique qu'il y a trois façons d'ajouter du contenu à une CALayer :

Pour la présente initiation, je me contente d'aborder la première technique, à savoir fournir directement une image à la CALayer.

Pour créer une CGImageRef à partir d'un fichier ou d'une URL représentant une image, le plus simple est d'utiliser une CGImageSourceRef qui sert d'intermédiaire entre une CGImageRef et une URL :

-(void)awakeFromNib
{
    // Ajout et activation d'une CALayer
    [animationView setLayer:[CALayer layer]];
    [animationView setWantsLayer:YES];
    
    // Ajout d'une image dans la CALayer
    NSString * imagePath =
        @"/System/Library/CoreServices/DefaultDesktop.jpg";
    CFURLRef imageURL = (CFURLRef)[NSURL fileURLWithPath:imagePath];
    CGImageSourceRef imageSource =
        CGImageSourceCreateWithURL(imageURL, NULL);
    CGImageRef image =
        CGImageSourceCreateImageAtIndex(imageSource, 0, NULL);
    CFRelease(imageSource);
    [[animationView layer] setContents:(id)image];
}

Compilez et lancez l'application... Voilà ! Vous savez afficher une image qui occupe toute la fenêtre en se déformant si nécessaire. Si vous souhaitez éviter les déformations, vous pouvez modifier la valeur de la propriété contentsGravity. Par exemple, ajoutez les lignes suivantes à la fin de -awakeFromNib :

    [[animationView layer] setContents:(id)image];

    // Placement de l'image
    [[animationView layer] setContentsGravity:kCAGravityResizeAspect];
}

Cette fois, l'image apparaît en entier et sans déformation, avec des marges sur deux des côtés lorsque la fenêtre n'a pas les mêmes proportions que l'image. Si vous préférez supprimer les marges et acceptez que l'image soit tronquée, la valeur à donner est kCAGravityResizeAspectFill. La valeur par défaut, qui donne le comportement que nous avons observé au début, est kCAGravityResize.

Il est aussi possible d'afficher l'image dans sa dimension naturelle. Il suffit de donner à la même propriété contentsGravity une autre valeur que kCAGravityResize.... Les valeurs possibles spécifient une position :

Enfin, si vous ne désirez pas travailler l'image entière mais seulement avec une partie recadrée, vous pouvez modifier la valeur de la propriété contentsRect. Il s'agit d'un rectangle qui spécifie la portion de l'image à utiliser. Les valeurs qui définissent ce rectangle (abscisse et ordonnée de l'origine, largeur et hauteur du rectangle) sont exprimées en fractions de la taille de l'image, c'est-à-dire entre 0 et 1. Essayez par exemple d'ajouter ces lignes à la fin de -awakeFromNib :

    // Placement de l'image
    [[animationView layer] setContentsGravity:kCAGravityResizeAspect];

    // Cadrage de l'image
    [[animationView layer]
     setContentsRect:CGRectMake(0.3, 0.2, 0.3, 0.3)];
}

À suivre...

Avec cet exercice, nous avons fait un tout premier pas dans CoreAnimation. Comme je l'ai déjà dit, il s'agit d'une auto-initiation que je souhaite partager avec vous. La prochaine étape consistera à modifier d'autres paramètres de l'image affichée et de voir comment CoreAnimation assure la transition progressive d'un réglage à l'autre.

Commentaires

Soyez le premier à commenter cet article.

Ajoutez un commentaire

Les commentaires sont destinés à répondre en public à l'article visé et à ses commentaires déjà publiés. C'est pourquoi seul un pseudonyme vous est demandé ici. Si vous souhaitez échanger avec moi en privé, merci de me laisser un message via le menu contact en haut de la page.

Archive

Rubriques

Abonnement