2009-02-05 7 views
0

J'ai un tableau noir d'UIImageViews que je veux faire défiler et passer rapidement d'un état «allumé» à un autre «éteint». J'ai écrit le code pour le faire dans une boucle for au lieu d'une méthode qui a été appelée lorsque l'utilisateur a tapé un UIButton (l'action du bouton).Permutation d'images UIImageView dans une boucle

est ici que la boucle:

for(int i = 0; i < [Images count]; i++) { 
    if(i > 0){ 
     [self toggleImageViewOff:[Images objectAtIndex:i - 1]]; 
    } 

    [self toggleImageViewOn:[Images objectAtIndex:i]]; 

    [NSThread sleepForTimeInterval:0.5f]; 
} 

L'interface utilisateur n'a pas mis à jour comme je m'y attendais que je ne ai vu que la dernière UIImageView dans la « marche ». J'ai pensé que la mise à jour du dessin des vues devait se produire dans le thread principal dans lequel ce code s'exécutait aussi. J'ai donc appris à propos de performSelectorInBackground: withObject:. L'exécution des méthodes toggleImageViewOn/Off en utilisant ceci a fait fonctionner la boucle. Le problème est que si je rends l'intervalle de sommeil trop court, je peux avoir une mise à jour "on" après un "off" avec des Threads fonctionnant dans le désordre. J'ai donc eu la brillante idée de déplacer toute la boucle avec le sommeil dans sa propre méthode et de l'appeler depuis la méthode d'action en utilisant performSelectorInBackground: withObject:. J'ai essayé cela et je suis de retour à ne pas avoir une vue à jour jusqu'à ce que la boucle soit terminée.

C'est une de longue haleine façon d'arriver à ma question:

Quelle est la meilleure façon d'animer ce pour garantir les feux de code sur/off dans le bon ordre et obtenir encore des mises à jour de vue, même à des vitesses élevées? (c'est-à-dire en boucle très rapidement)

J'ai essayé de penser à comment je le ferais avec CoreAnimation, mais je n'arrive pas à comprendre comment le faire.

pour le bonus, voici les méthodes de Toggle:

- (void)toggleImageViewOn:(UIImageView *)theImageView { 
    [theImageView setImage:[UIImage imageNamed:@"on.png"]]; 
} 

- (void)toggleImageViewOff:(UIImageView *)theImageView { 
    [theImageView setImage:[UIImage imageNamed:@"off.png"]]; 
} 

Répondre

0

Vous êtes sur la bonne voie en déplaçant la boucle vers un thread d'arrière-plan, mais vous devez également vous assurer que vous donnez à la boucle d'exécution principale une chance de mettre à jour l'interface utilisateur. Vous devriez être en mesure de remplacer les appels directs à toggleImageViewOn: et toggleImageViewOff: avec quelque chose comme

[self performSelectorOnMainThread:@selector(toggleImageViewOn:) withObject:[Images objectAtIndex:i] waitUntilDone:NO]; 

Cela fera la mise à jour de l'interface utilisateur sur le thread principal, et de ne pas attendre que la mise à jour se fait vous donner la course principale boucle une chance d'atteindre sa fin. Vous rencontrez le même problème avec des choses comme les barres de progression, où elles ne changeront pas jusqu'à ce que la boucle se termine, sauf si vous effectuez vos mises à jour à partir d'un thread d'arrière-plan avec un appel de mise à jour de l'interface utilisateur.

0

Hey Patrick. Jetez un oeil à la propriété animationImages de UIImageView, ainsi qu'aux propriétés animationRepeatCount et animationDuration. Si vous mettez vos images on/off dans un tableau et que vous les affectez en tant que propriété animationImages, vous devriez pouvoir contrôler la répétition et la durée pour obtenir l'effet désiré.

Espérons que ça aide!

0

Merci pour cela. J'ai déjà regardé dans la propriété animationImages de UIIMageView. Ce n'est pas exactement ce que je tente de faire. Je pédale entre plusieurs UIImageView placés les uns près des autres pour donner l'impression qu'une lumière se déplace entre eux et passe par-dessus. Donc, l'animation individuelle d'UIImageView est séparée l'une de l'autre car j'ai besoin d'échanger l'image si nécessaire dans le code.

2

Avez-vous configuré un contexte d'animation (méthode de classe UIView fait cela) autour de cette boucle? Sans cela, les changements sont immédiats et non animés.

+0

Bill, J'ai essayé autour de la boucle avec [UIView beginAnimations: @ contexte "animation": nil]; et [UIView commitAnimations]; Mais cela n'a pas eu d'effet. Tout ce que je vois est une énorme pause dans l'interface utilisateur tandis que la boucle va et puis "bang", juste la dernière image est "sur". –

+1

hm, imageview ne doit pas animer sa propriété 'image' je suppose, bummer. Vous pouvez envisager d'utiliser des calques ici car ils animent la modification du contenu (avec un fondu enchaîné par défaut). Ou vous pouvez faire la chose vue "recommandée" et ajouter un "aperçu" qui contiendrait soit l'affichage de l'image on ou off –

+0

cool Bill Dudney est sur SO maintenant. bienvenue à bord j'aime vraiment votre livre sur iPhone dev. –

0

Appeler peformSelectorOnMainThread: withObject: waitUntilDone: de la boucle sur le thread d'arrière-plan met effectivement à jour la vue aussi rapidement que je peux penser que je n'aurai jamais besoin. Je suis curieux de savoir pourquoi je dois faire l'échange UIImageView sur le thread principal? Pourquoi ne pas le changer sur le thread d'arrière-plan, puis en utilisant sleepForTimeInterval de NSThread permettre au thread principal de mettre à jour le dessin de toute façon? Je suppose que j'ai besoin d'aller lire sur la boucle d'exécution et où les mises à jour de dessin se produisent.

Merci beaucoup pour votre aide. (Je vais aussi essayer quelques suggestions additionnelles de Bill Dudney, qui fonctionneront selon CoreAnimation)

+0

L'appel du code de dessin n'est sûr que lorsqu'il est appelé depuis le thread principal. Je suis surpris que cela a fonctionné du tout :) – rpetrich

1

Le problème est que vous ne donnez pas le temps UIImages de dessiner. Le code de dessin est optimisé pour ne dessiner que ce dont vous avez besoin - le rendu de toutes ces étapes intermédiaires est optimisé.

Dormir le filetage principal ne lui donne pas la chance de fonctionner.

Bill a raison de dire que vous devez configurer un contexte d'animation autour de votre boucle. Cela permettra de capturer tous les changements UIView que vous faites, puis les jouer. Le moyen le plus simple de le faire est d'utiliser Core Animation. L'animation de base 'enregistrements' change dans UIElemenets et les rejoue. Votre code (sans le sommeil) fonctionnera très bien dans un bloc Core Animation.

Apple ont un livre de cuisine raisonnable pour Core Animation on their site

+0

Appel de la permutation sur un thread d'arrière-plan pour faire l'échange sur le thread principal, puis le sommeil permet la mise à jour. Je vais essayer d'utiliser UIView autour des UIImages puis faire un bloc CA aussi. UIIMageView n'expose apparemment pas l'échange d'image à CA. –