125 votes

Ce qui est le plus robuste de la force d'une UIView pour redessiner?

J'ai un UITableView avec une liste d'éléments. En sélectionnant un élément pousse un viewController qui procède alors à effectuer les opérations suivantes. à partir de la méthode viewDidLoad j'ai d'incendie à une URLRequest pour les données qui sont requises par une de mes sous-vues - une sous-classe UIView avec drawRect remplacée. Lorsque les données arrivent à partir du nuage, j'ai commencer la construction de mon point de vue de la hiérarchie. la sous-classe en question reçoit les données et la méthode drawRect a maintenant tout ce qu'il doit rendre.

Mais.

Parce que je ne l'appelez pas drawRect explicitement - Cacao-Toucher les poignées que je n'ai aucun moyen de les informer de Cacao-Touch que j'ai vraiment, vraiment envie cette sous-classe UIView à rendre. Quand? Maintenant, ce serait bien!!!

J'ai essayé [mavue setNeedsDisplay]. Ce genre de travaux parfois de. Très inégale.

J'ai lutte avec cela pendant des heures et des heures. Quelqu'un qui merci de me fournir un rocher solide, garanti approche à forcer un UIView un nouveau rendu.

Voici l'extrait de code qui se nourrit des données de la vue:

// Create the subview
self.chromosomeBlockView = [[[ChromosomeBlockView alloc] initWithFrame:frame] autorelease];

// Set some properties
self.chromosomeBlockView.sequenceString 	= self.sequenceString;
self.chromosomeBlockView.nucleotideBases    = self.nucleotideLettersDictionary;

// Insert the view in the view hierarchy
[self.containerView          addSubview:self.chromosomeBlockView];
[self.containerView bringSubviewToFront:self.chromosomeBlockView];

// A vain attempt to convince Cocoa-Touch that this view is worthy of being displayed ;-)
[self.chromosomeBlockView setNeedsDisplay];

Cheers, Doug

197voto

Rob Napier Points 92148

La garantie, solide comme le roc moyen de forcer l' UIView re-render est - [myView setNeedsDisplay]. Si vous rencontrez des problèmes avec ça, vous êtes probablement en cours d'exécution dans l'une de ces questions:

  • Vous appelez avant de vous avez réellement les données, ou votre -drawRect: est plus de mise en cache quelque chose.

  • Vous vous attendez à la vue de tirer au moment de l'appel de cette méthode. Il est intentionnellement en aucune façon à la demande de "droit de tirage maintenant cette seconde" à l'aide du Cacao en dessinant système de. Susceptibles de perturber la vue d'ensemble système de composition, corbeille de performance et susceptibles de créer toutes sortes de quelques artefacts. Il y a seulement des manières de dire "ce doit être établi, dans le prochain tirage du cycle."

Si ce que vous avez besoin est "un peu de logique, de dessiner, d'autres, plus logique", alors vous avez besoin de mettre le "des plus logique" dans une méthode séparée et d'appeler à l'aide -performSelector:withObject:afterDelay: avec un retard de 0. Qui mettez-y un peu plus de logique" après le prochain tirage du cycle. Voir cette question pour un exemple de ce type de code, et un cas où il pourrait être nécessaire (bien qu'il est généralement préférable de chercher d'autres solutions, si possible, car cela complique le code).

Si vous ne pensez pas que les choses deviennent tirés, mettre un point d'arrêt en -drawRect: et de voir quand vous êtes appelé. Si vous appelez -setNeedsDisplay, mais -drawRect: n'est pas appelé dans la prochaine boucle d'événements, puis creuser dans votre vue de la hiérarchie et assurez-vous que vous n'êtes pas d'essayer de déjouer est quelque part. La sur-l'intelligence est la cause n ° 1 de mauvais dessin dans mon expérience. Quand vous pensez que vous connaissez la meilleure façon de tromper le système en faire ce que vous voulez, vous obtenez généralement il faire exactement ce que vous ne voulez pas.

53voto

Werner Altewischer Points 3439

J'ai eu un problème avec un grand délai entre l'appel de setNeedsDisplay et drawRect: (5 secondes). Il s'est avéré que j'ai appelé setNeedsDisplay dans un autre thread que le thread principal. Après le déplacement de cet appel pour le thread principal le retard s'en alla.

J'espère que cela est de peu d'aide.

21voto

Slipp D. Thompson Points 6293

Si vous voulez vraiment le point de vue pour le rendu de droit-ici-maintenant vous avez juste besoin de configurer l' CALayer votre UIView.

Dans votre sous-classe UIView, créer un - display méthode qui indique à la couche que "oui, il doit afficher", puis "faire en sorte":

/// Redraws the view's contents immediately.
/// Serves the same purpose as the display method in GLKView.
/// Not to be confused with CALayer's display method.
- (void)display
{
    CALayer *layer = self.layer;
    [layer setNeedsDisplay];
    [layer displayIfNeeded];
}

Aussi mettre en œuvre un - drawLayer:inContext: méthode qui vais appeler votre privé/interne méthode de dessin (qui fonctionne depuis tous les UIView est un CALayerDelegate), et de fournir un passe- - drawRect: mise en œuvre:

/// Called by our CALayer when it wants us to draw (in compliance with the CALayerDelegate protocol).
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context
{
    UIGraphicsPushContext(context);
    [self internalDrawWithRect:self.bounds];
    UIGraphicsPopContext();
}

/// For compatibility, if something besides our display method asks for draw.
- (void)drawRect:(CGRect)rect
{
    [self drawMyViewWithRect:rect];
}

/// Internal drawing method; naming's up to you.
- (void)internalDrawWithRect:(CGRect)rect
{
    // @fillin: draw draw draw
}

Et maintenant, juste appelez - [myView display] chaque fois que vous avez vraiment, vraiment besoin de dessiner. display racontera l' CALayer de displayIfNeeded, ce qui fera de façon synchrone de retour d'appel dans notre coutume drawLayer:inContext: et de faire le dessin en internalDrawWithRect:, mise à jour de visual avec ce qui est établi dans le contexte avant de passer.

5voto

dreamzor Points 2327

J'ai eu le même problème, et toutes les solutions à partir de ou Google n'a pas de travail pour moi. Généralement, setNeedsDisplay fonctionne, mais quand cela ne fonctionne pas...
J'ai essayé de les appeler, setNeedsDisplay de la vue juste de toutes les manières possibles tous les threads et des trucs - toujours pas de succès. Nous savons, comme l'a dit Rob, qui

"ce doit être établi, dans le prochain tirage du cycle."

Mais pour quelque raison il ne serait pas tirer de cette époque. Et la seule solution que j'ai trouvé est de l'appeler manuellement après un certain temps, pour laisser quelque chose qui bloque le tirage au sort se passer de loin, comme ceci:

dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 
                                        (int64_t)(0.005 * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
    [viewToRefresh setNeedsDisplay];
});

C'est une bonne solution si vous n'avez pas besoin de la vue de redessiner vraiment souvent. Sinon, si vous êtes en train de faire quelque mouvement (action) des choses, il n'y a généralement pas de problème avec tout le qualifiant setNeedsDisplay.

J'espère que ça va aider quelqu'un qui est perdu, comme je l'étais.

0voto

Miki Points 1

Eh bien, je sais que cela pourrait être un grand changement, ou même ne convient pas à votre projet, mais ne vous considérez pas les pousser jusqu'à ce que vous avez déjà les données? De cette façon, vous ne devez dessiner la vue et de l'expérience de l'utilisateur sera également mieux que le poussoir se déplace en est déjà chargé.

La façon dont vous le faire est dans l' UITableView didSelectRowAtIndexPath vous asynchrone demander les données. Une fois que vous recevez la réponse, vous effectuez manuellement la séquence et de transmettre les données à votre viewController en prepareForSegue. En attendant, vous pouvez montrer certains de l'indicateur d'activité, pour la simple indicateur de chargement de vérifier https://github.com/jdg/MBProgressHUD

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X