J'ai un UITableView avec une liste d'articles. La sélection d'un élément pousse un viewController qui procède ensuite aux opérations suivantes. from method viewDidLoad Je déclenche une URLRequest pour les données requises par l'une de mes sous-vues - une sous-classe UIView avec drawRect remplacé. Lorsque les données arrivent du cloud, je commence à construire ma hiérarchie de vues. la sous-classe en question reçoit les données et sa méthode drawRect a maintenant tout ce dont elle a besoin pour le rendu.
Mais.
Parce que je n'appelle pas drawRect explicitement - Cocoa-Touch gère cela - je n'ai aucun moyen d'informer Cocoa-Touch que je veux vraiment, vraiment que cette sous-classe UIView soit rendue. Quand? Ce serait bien maintenant!
J'ai essayé [myView setNeedsDisplay]. Cela fonctionne un peu parfois. Très irrégulier.
Je lutte avec ça depuis des heures et des heures. Quelqu'un pourrait-il s'il vous plaît me fournir une approche solide et garantie pour forcer un nouveau rendu UIView.
Voici l'extrait de code qui fournit des données à 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];
Salut, Doug
la source
setNeedsDisplay
appel et l'appel réel dedrawRect:
. Bien que la fiabilité des appels soit là, je n'appellerais pas cela la solution «la plus robuste» - une solution de dessin robuste devrait, en théorie, faire tout le dessin immédiatement avant de revenir au code client qui demande le tirage au sort.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 thread différent du thread principal. Après avoir déplacé cet appel vers le thread principal, le délai a disparu.
J'espère que cela aidera.
la source
La manière garantie de remboursement, en béton armé solide pour forcer une vue à dessiner de manière synchrone (avant de revenir au code appelant) est de configurer les
CALayer
interactions de la avec votreUIView
sous - classe.Dans votre sous-classe UIView, créez une
displayNow()
méthode qui indique au calque de « définir le cap pour l'affichage » puis de « faire en sorte »:Rapide
Objectif c
Implémentez également une
draw(_: CALayer, in: CGContext)
méthode qui appellera votre méthode de dessin privée / interne (qui fonctionne puisque toutUIView
est aCALayerDelegate
) :Rapide
Objectif c
Et créez votre
internalDraw(_: CGRect)
méthode personnalisée , avec une sécurité intégréedraw(_: CGRect)
:Rapide
Objectif c
Et maintenant, il suffit d'appeler
myView.displayNow()
chaque fois que vous en avez vraiment besoin pour dessiner (par exemple à partir d'unCADisplayLink
rappel) . NotredisplayNow()
méthode indiqueraCALayer
àdisplayIfNeeded()
, qui rappellera de manière synchrone notredraw(_:,in:)
et effectuera le dessininternalDraw(_:)
, mettant à jour le visuel avec ce qui est dessiné dans le contexte avant de continuer.Cette approche est similaire à celle de @ RobNapier ci-dessus, mais présente l'avantage d'appeler
displayIfNeeded()
en plus desetNeedsDisplay()
, ce qui la rend synchrone.Cela est possible parce que
CALayer
s exposent plus de fonctionnalités de dessin que ne le fontUIView
- les couches sont de niveau inférieur aux vues et conçues explicitement dans le but de dessiner hautement configurable dans la mise en page et (comme beaucoup de choses dans Cocoa) sont conçues pour être utilisées de manière flexible ( en tant que classe parente, ou en tant que délégant, ou en tant que pont vers d'autres systèmes de dessin, ou simplement seuls). Une bonne utilisation duCALayerDelegate
protocole rend tout cela possible.Pour plus d'informations sur la configurabilité de
CALayer
s, reportez-vous à la section Configuration des objets de couche du Guide de programmation de l'animation de base .la source
drawRect:
dit explicitement "Vous ne devez jamais appeler cette méthode directement vous-même." En outre, CALayerdisplay
dit explicitement " N'appelez pas cette méthode directement." Si vous souhaitez dessinercontents
directement sur les calques de manière synchrone, il n'est pas nécessaire de violer ces règles. Vous pouvez simplement dessiner sur le calque àcontents
tout moment (même sur les fils d'arrière-plan). Ajoutez simplement une sous-couche à la vue pour cela. Mais c'est différent de le mettre à l'écran, qui doit attendre le bon moment de composition.contents
("Si l'objet de calque est lié à un objet de vue, vous devez éviter de définir le contenu de cette propriété directement. L'interaction entre les vues et les calques résulte généralement dans la vue remplaçant le contenu de cette propriété lors d'une mise à jour ultérieure. ") Je ne recommande pas particulièrement cette approche; un dessin prématuré nuit aux performances et à la qualité du dessin. Mais si vous en avez besoin pour une raison quelconque,contents
comment l'obtenir.drawRect:
directement. Il n'était pas nécessaire de démontrer cette technique et a été corrigé.contents
technique que vous suggérez… semble séduisante. J'ai essayé quelque chose comme ça au départ, mais je n'ai pas pu le faire fonctionner, et j'ai trouvé que la solution ci-dessus était beaucoup moins de code sans aucune raison de ne pas être aussi performante. Cependant, si vous avez une solution de travail pour l'contents
approche, je serais intéressé à la lire (il n'y a aucune raison pour laquelle vous ne pouvez pas avoir deux réponses à cette question, non?)display
. C'est juste une méthode publique personnalisée dans une sous-classe UIView, tout comme ce qui est fait dans GLKView (une autre sous-classe UIView, et la seule écrite par Apple que je connaisse qui nécessite la fonctionnalité DRAW NOW! ).J'ai eu le même problème et toutes les solutions de SO ou de Google ne fonctionnaient pas pour moi. Habituellement,
setNeedsDisplay
cela fonctionne, mais quand ce n'est pas le cas ...J'ai essayé d'appeler
setNeedsDisplay
la vue de toutes les manières possibles à partir de tous les threads et trucs possibles - toujours sans succès. Nous savons, comme Rob l'a dit, queMais pour une raison quelconque, il ne dessinerait pas cette fois. Et la seule solution que j'ai trouvée est de l'appeler manuellement après un certain temps, pour laisser passer tout ce qui bloque le tirage au sort, comme ceci:
C'est une bonne solution si vous n'avez pas besoin que la vue soit redessinée très souvent. Sinon, si vous faites des choses en mouvement (action), il n'y a généralement aucun problème avec le simple appel
setNeedsDisplay
.J'espère que cela aidera quelqu'un qui est perdu là-bas, comme moi.
la source
Eh bien, je sais que cela pourrait être un grand changement ou même pas adapté à votre projet, mais avez-vous envisagé de ne pas effectuer le push tant que vous n'avez pas déjà les données ? De cette façon, vous n'avez besoin de dessiner la vue qu'une seule fois et l'expérience utilisateur sera également meilleure - le push se déplacera déjà chargé.
La façon dont vous faites cela consiste à
UITableView
didSelectRowAtIndexPath
demander les données de manière asynchrone. Une fois que vous recevez la réponse, vous effectuez manuellement la transition et transmettez les données à votre viewController dansprepareForSegue
. En attendant, vous voudrez peut-être afficher un indicateur d'activité, pour un simple indicateur de chargement, vérifiez https://github.com/jdg/MBProgressHUDla source