IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Développement iOS Discussion :

[help] Créer une animation


Sujet :

Développement iOS

  1. #1
    Membre habitué
    Homme Profil pro
    Etudiant
    Inscrit en
    Février 2010
    Messages
    115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Etudiant

    Informations forums :
    Inscription : Février 2010
    Messages : 115
    Points : 139
    Points
    139
    Par défaut [help] Créer une animation
    Hello,

    J'essaye d'apprendre les bases pour créer de petites animations (le but est de créer une petite progressbar en baton), mais je dois avouer que j'ai du mal à comprendre...

    Voila ce que j'ai compris :
    - On peut utiliser les NSBezierPath pour créer à peu près toutes les formes que l'on veut (pour ma part ça sera probablement des rectangles arrondi)

    - On doit utiliser une CAKeyframeAnimation pour pouvoir gérer l'animation
    - Avec la propriété "keyTimes" on peut gérer les timmings (dans mon exemple je vais mettre @[0.33,0.66,1] si j'ai bien compris)

    Par contre ce que je n'ai pas du tout saisi :
    - Comment afficher concrètement une NSBezierPath à l'écran (méthode "fill" ?)
    - Comment utiliser la propriété "values" de la classe CAKeyframeAnimation.
    - Arriver à mixer les 2 pour que ça marche :p

    En gros l'idée serait de créer une progress bar (qui se répète à l'infini) comme ceci :

    frame 1: |
    frame 2: ||
    frame 3: |||

    Si quelqu'un est prêt à passer un petit bout de temps pour m'expliquer...

    Merci d'avance

    PS : je crois que je me suis planté de section car ma cible serait plutôt l'iphone :s

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Attention:
    1. C'est juste une solution basique: un écran d'attente avec une barre qui change de couleurs
    2. C'est juste une solution basique: il faudra l'adapter à ton code
    3. C'est juste une solution basique, validée jusqu'à iOS 6
    4. tu vas travailler un peu parce qu'il y a des trucs à connaître comme GCD et le mécanisme de mise à jour d'une UIView


    Donc:
    1) Il faut dans ton code une classe qui dérive d'UIView
    Tu t'aperçois que:
    1. c'est le singleton data [AppData] qui lance et arrête l'animation avec les méthodes start_animation et stop_animation
    2. c'est la méthode update_screen qui va être appelée à intervalles réguliers


    Doute: il faut utiliser le méthode mach_absolute_time() parce qu'elle ne s’interrompe pas avec le réseau (ou un truc comme cela)


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    //
    //  Waiting_Screen.h
    
    #import <Foundation/Foundation.h>
    
    
    @interface Waiting_Screen: UIView
    {
    @private
    
    	BOOL is_busy;
    
    	// Clock
    	double delta;
    	uint64_t last_time;
    
    	float current_percent;
    
    	short begin_R;
    	short begin_G;
    	short begin_B;
    	float begin_percent;
    	short end_R;
    	short end_G;
    	short end_B;
    	float end_percent;
    }
    
    
    - (id) initWithFrame:(CGRect) frame;
    
    - (void) drawRect:(CGRect) rect;
    
    - (void) update_screen;
    
    - (void) start_animation;
    
    - (void) stop_animation;
    
    @end
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    //
    //  Waiting_Screen.m
    
    #import "Waiting_Screen.h"
    
    #import <QuartzCore/QuartzCore.h>
    #import <mach/mach_time.h>
    
    #import "../AppData.h"
    #import "../Utils/Utils.h"
    
    
    @implementation Waiting_Screen
    
    - (id) initWithFrame:(CGRect) frame {
    	self = [super initWithFrame:frame];
    
    	if (self != nil) {
    		// Initialization code
    		current_percent = 0.0f;
    
    		self.backgroundColor = [UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.0f];
    
    		is_busy = NO;
    
    		mach_timebase_info_data_t info;
    		mach_timebase_info(&info);
    
    		delta = (double) (info.numer / info.denom / 1000000000.0);
    		last_time = 0;
    
    		begin_R = begin_G = begin_B = 0.0f;
    		end_R = end_G = end_B = 0.0f;
    		begin_percent = 0.0f; end_percent = 1.0f;
    	}
    
    	return self;
    }
    
    
    // Only override drawRect: if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    - (void) drawRect:(CGRect) rect {
    	// Drawing code
    	[super drawRect:rect];
    
    	CGContextRef context = UIGraphicsGetCurrentContext();
    
    	CGRect frame = CGRectMake(rect.origin.x, rect.origin.y,rect.size.width, rect.size.height);
    
    	CGContextSetRGBFillColor(context, 1.0f, 1.0f, 1.0f, 1.0f);
    	CGContextFillRect(context, frame);
    
    	float current_R = (begin_R + ((current_percent - begin_percent) * (end_R - begin_R) / (end_percent - begin_percent)));
    	float current_G = (begin_G + ((current_percent - begin_percent) * (end_G - begin_G) / (end_percent - begin_percent)));
    	float current_B = (begin_B + ((current_percent - begin_percent) * (end_B - begin_B) / (end_percent - begin_percent)));
    	float position = (self.frame.size.width * current_percent / 100.0f);
    
    	CGContextSetLineWidth(context, 2);
    	CGContextSetRGBStrokeColor(context, (current_R / 255.0f), (current_G / 255.0f), (current_B / 255.0f), 1.0f);
    
    	CGContextMoveToPoint(context, 0, ((self.frame.size.height / 2.0) - 1.0f));
    	CGContextAddLineToPoint(context, position, ((self.frame.size.height / 2.0) - 1.0f));
    	CGContextStrokePath(context);
    
    //	DLOG( (@"Waiting_Screen::drawRect - (0 -> %f) (%f, %f, %f)", position, current_R, current_G, current_B) )
    }
    
    
    - (void) update_screen {
    	if (is_busy) { return; }
    
    	is_busy = YES;
    
    	uint64_t now = mach_absolute_time();
    	if (last_time == 0) { last_time = now; }
    
    	double delta_time = (double) ((now - last_time) * delta);
    
    	if (delta_time > (TIME_WAITING_DURATION / 1000.0f)) { delta_time = (TIME_WAITING_DURATION / 1000.0f); }
    
    	current_percent = (0.0f + (delta_time * 100.0f / (TIME_WAITING_DURATION / 1000.0f)));
    
    	if (current_percent >= 99.0f) { last_time = now; }
    
    //	DLOG( (@"Waiting_Screen::update_screen - Current Percent: %f", current_percent) )
    
    	if ((current_percent > 0) && (current_percent < 25.0f)) {
    		begin_R = 255; begin_G = 255; begin_B = 255;
    		end_R = 246; end_G = 3; end_B = 220;
    		begin_percent = 0.0f; end_percent = 25.0f;
    	} else if ((current_percent > 25.0f) && (current_percent < 50.0f)) {
    		begin_R = 246; begin_G = 3; begin_B = 220;
    		end_R = 246; end_G = 101; end_B = 3;
    		begin_percent = 25.0f; end_percent = 50.0f;
    	} else if ((current_percent > 50.0f) && (current_percent < 75.0f)) {
    		begin_R = 246; begin_G = 101; begin_B = 3;
    		end_R = 249; end_G = 21; end_B = 0;
    		begin_percent = 50.0f; end_percent = 75.0f;
    	} else if (current_percent > 75.0f) {
    		begin_R = 249; begin_G = 21; begin_B = 0;
    		end_R = 254; end_G = 227; end_B = 25;
    		begin_percent = 75.0f; end_percent = 100.0f;
    	}
    
    	[self setNeedsDisplay];
    
    	is_busy = NO;
    }
    
    
    - (void) start_animation {
    	AppData* data = [AppData sharedData];
    	[data add_graphic_update:self];
    }
    
    
    - (void) stop_animation {
    	AppData* data = [AppData sharedData];
    	[data stop_graphic_update];
    }
    
    @end

    2) La partie intéressante du singleton AppData que tu devras adapter, voire même supprimer la notion de singleton
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    //
    //  AppData.h
    
    #import <Foundation/Foundation.h>
    
    @class Graphic_Operation;
    
    
    @interface AppData: NSObject
    {
    @public
    
    	// Thread
    	NSOperationQueue* operation_queue;
    	Graphic_Operation* graphic_operation;
    
    	BOOL is_initialized;
    }
    
    
    - (void) cleanup_thread;
    
    // Application Delegates
    - (void) applicationDidEnterBackground;
    
    - (BOOL) applicationWillEnterForeground;
    
    // Thread
    - (void) add_graphic_update:(id) delegate;
    
    - (void) stop_graphic_update;
    
    // Singleton
    + (AppData*) sharedData;
    
    @end
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    //
    //  AppData.m
    
    #import "AppData.h"
    
    #import "Threads/Graphic_Operation.h"
    #import "Utils/Utils.h"
    
    
    @implementation AppData
    
    #pragma mark - Life Management
    
    - (id) initData {
    	self = [super init];
    
    	if (self != nil) {
    		// Thread
    		operation_queue = nil;
    		graphic_operation = nil;
    
    		is_initialized = NO;
    	}
    
    	return self;
    }
    
    
    - (void) dealloc {
    	[self cleanup_thread];
    
    	[super dealloc];
    }
    
    
    - (void) cleanup_thread {
    	[self stop_graphic_update];
    
    	if (operation_queue != nil) {
    		[operation_queue cancelAllOperations];
    		[operation_queue waitUntilAllOperationsAreFinished];
    	}
    
    	RELEASE(operation_queue)
    }
    
    
    #pragma mark - Application Delegates
    
    - (void) applicationDidEnterBackground {
    	DLOG( (@"AppData::applicationDidEnterBackground") )
    
    	[self cleanup_thread];
    
    	is_initialized = NO;
    }
    
    
    - (BOOL) applicationWillEnterForeground {
    	if (is_initialized) { return YES; }
    
    	DLOG( (@"AppData::applicationWillEnterForeground") )
    
    	// Thread
    	operation_queue = nil;
    	graphic_operation = nil;
    
    	is_initialized = YES;
    
    	return YES;
    }
    
    
    #pragma mark - Thread
    
    - (void) add_graphic_update:(id) delegate {
    	if (graphic_operation != nil) { return; }
    
    	if (operation_queue == nil) {
    		operation_queue = [[NSOperationQueue alloc] init];
    	}
    
    	graphic_operation = [[Graphic_Operation alloc] init_operation];
    	[graphic_operation set_delegate:delegate];
    	
    	[operation_queue addOperation:graphic_operation];
    }
    
    
    - (void) stop_graphic_update {
    	if (graphic_operation != nil) {
    		[graphic_operation cancel];
    		[graphic_operation waitUntilFinished];
    
    		[graphic_operation release];
    	}
    	graphic_operation = nil;
    }
    
    
    #pragma mark - Singleton
    
    static AppData* sharedData = nil;
    
    
    - (id) autorelease {
    	return self;
    }
    
    
    + (id) allocWithZone:(NSZone*) zone {
    	return [[self sharedData] retain];
    }
    
    
    - (id) copyWithZone:(NSZone*) zone {
    	return self;
    }
    
    
    + (AppData*) sharedData {
    	if (sharedData == nil) {
    		sharedData = [[super allocWithZone:NULL] initData];
    	}
    
    	return sharedData;
    }
    
    
    - (oneway void) release {}
    
    
    - (id) retain {
    	return self;
    }
    
    
    - (NSUInteger) retainCount {
    	return NSUIntegerMax;
    }
    
    @end

    3) Si tu regardes le code, il faut créer une classe NSOperation

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    //
    //  Graphic_Operation.h
    
    #import <Foundation/Foundation.h>
    
    
    @interface Graphic_Operation: NSOperation
    {
    @private
    
    	id delegate;	
    }
    
    
    - (id) init_operation;
    
    - (void) set_delegate:(id) new_delegate;
    
    @end
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    //
    //  Graphic_Operation.m
    
    #import "Graphic_Operation.h"
    
    #import "../Utils/Utils.h"
    
    
    @implementation Graphic_Operation
    
    - (id) init_operation {
    	self = [super init];
    
    	if (self != nil) {
    		delegate = nil;
    	}
    
    	return self;
    }
    
    
    - (void) dealloc {
    	delegate = nil;
    
    	[super dealloc];
    }
    
    
    - (void) set_delegate:(id) new_delegate {
    	delegate = new_delegate;
    }
    
    
    - (void) main {
    	if (delegate == nil) { return; }
    
    	[delegate retain];
    
    	DLOG( (@"Graphic_Operation Begin") )
    
    	NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    
    	while (!self.isCancelled) {
    		[NSThread sleepForTimeInterval:0.05f];
    
    		if (!self.isCancelled) {
    			[delegate performSelectorOnMainThread:@selector(update_screen) withObject:nil waitUntilDone:NO];
    		}
    	}
    
    	[pool drain];
    
    	DLOG( (@"Graphic_Operation End") )
    
    	[delegate release];
    
    	delegate = nil;
    }
    
    @end

    4) Comment j'ai fait pour utiliser tout cela?
    Dans mon controlleur principal [AppControler], j'ai ajouté 2 méthodes pour afficher et retirer cet écran [plus un attribut UIView* current_view].
    Ainsi je peux l'appeler d'un peu partout

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    //
    //  AppController.m
    
    #import "AppController.h"
    
    #import "AppData.h"
    #import "View/Waiting_Screen.h"
    
    
    @implementation AppController
    
    ...
    
    #pragma mark - Waiting Screens
    
    - (void) add_waiting_screen:(BOOL) full_screen {
    	if (current_view == nil) { return; }
    
    	[self remove_waiting_screen];
    
    	AppData* data = [AppData sharedData];
    
    	if (full_screen) {
    		waiting_screen = [[Waiting_Screen alloc] initWithFrame:CGRectMake(0.0f, 0.0f, data->app_width, data->app_height)];
    	} else {
    		GET_CLIENT_AREA
    
    		waiting_screen = [[Waiting_Screen alloc] initWithFrame:CGRectMake(x, y, width, height)];
    	}
    
    	[self->current_view addSubview:waiting_screen];
    	[waiting_screen start_animation];
    }
    
    
    - (void) remove_waiting_screen {
    	if (current_view == nil) { return; }
    
    	if (waiting_screen != nil) {
    		[waiting_screen stop_animation];
    		[waiting_screen removeFromSuperview];
    		[waiting_screen release];
    	}
    	waiting_screen = nil;
    }
    
    @end

    5) Et si tu demandes, dans Utils.h

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    #ifdef DEBUG
    #define DLOG( X ) NSLog X;
    #else
    #define DLOG( X )
    #endif
    
    
    #define RELEASE(object) \
    	if (object != nil) { \
    		[object release]; \
    	} \
    	object = nil;
    
    
    // Hardcoded
    #define GET_CLIENT_AREA short x = 0, y = 0, width = 0, height = 0; \
    \
    		if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { \
    			x = 0; y = 34; width = 480; height = 286; \
    		} else { \
    			x = 0; y = 122; width = 1024; height = 646; \
    		}
    
    
    typedef enum {
    	TIME_WAITING_DURATION = 4000
    } Constant;

Discussions similaires

  1. Créer une animation de sprite sous Eclipse
    Par HekThor dans le forum Développement 2D, 3D et Jeux
    Réponses: 2
    Dernier message: 24/10/2008, 19h30
  2. Créer une animation
    Par soldat yul dans le forum Flash
    Réponses: 7
    Dernier message: 16/07/2007, 17h59
  3. Créer une animation
    Par zappa37 dans le forum Calcul scientifique
    Réponses: 4
    Dernier message: 13/01/2007, 21h22
  4. [GD] Est-il possible de créer une animation ?
    Par JavaAcro dans le forum Bibliothèques et frameworks
    Réponses: 4
    Dernier message: 02/03/2006, 16h33
  5. [FLASH MX2004] Aide pour créer une animation
    Par SnakeTales dans le forum Flash
    Réponses: 5
    Dernier message: 04/08/2005, 10h50

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo