Réponses:
Pour mieux comprendre les réponses fournies par François BOURLIEUX et Dalvik, je vous suggère de jeter un œil à ce superbe diagramme du cycle de vie des vues par Arpit Mathur :
TextView
. Je pensais qu'ils voulaient peut-être dessiner le View
pour la dernière fois avant de modifier ses paramètres liés à la mise en page, mais cela n'a pas vraiment de sens si nous pensons que ces appels sont invoqués dans un ordre différent (et ils appellent invalidate()
juste après requestLayout()
dans TextView
ainsi que). Peut-être que cela mérite une autre question sur StackOverflow :)?
invalidate()
et requestLayout()
) correctement. Le but de ces méthodes est de dire View
quelle sorte d' invalidation (comme vous l'avez appelée) s'est produite. Ce n'est pas comme si le View
décidait du chemin à suivre après avoir appelé l'une de ces méthodes. La logique derrière le choix du View
-lifecycle-path est le choix de la méthode appropriée pour s'appeler. S'il y a quelque chose lié au changement de taille - requestLayout()
devrait être appelé, s'il n'y a qu'un changement visuel sans changement de taille - vous devriez appeler invalidate()
.
View
d'une certaine manière, par exemple, vous obtenez le courantLayoutParams
de a View
et vous les modifiez, mais n'appelez PAS l' un requestLayout
ou l' autre setLayoutParams
(qui appelle en requestLayout
interne), alors vous pouvez appeler invalidate()
autant que vous le souhaitez, et le View
ne passera pas par le processus de mise en page de la mesure et ne changera donc pas sa taille. Si vous ne dites pas View
que sa taille a changé (avec un requestLayout
appel de méthode), alors le View
supposera que ce n'est pas le cas, et le onMeasure
et onLayout
ne sera pas appelé.
invalidate()
L'appel invalidate()
est effectué lorsque vous souhaitez planifier un rafraîchissement de la vue. Il en résultera onDraw
éventuellement un appel (bientôt, mais pas immédiatement). Un exemple de quand une vue personnalisée l'appellerait est quand une propriété de couleur de texte ou d'arrière-plan a changé.
La vue sera redessinée mais la taille ne changera pas.
requestLayout()
Si quelque chose dans votre vue change et affecte la taille, vous devez appeler requestLayout()
. Cela déclenchera onMeasure
et onLayout
non seulement pour ce point de vue , mais tout le chemin jusqu'à la ligne pour les vues parent.
Il requestLayout()
n'est pas garanti qu'unonDraw
appel aboutisse à un (contrairement à ce que le diagramme de la réponse acceptée implique), il est donc généralement combiné avec invalidate()
.
invalidate();
requestLayout();
Un exemple de ceci est lorsqu'une étiquette personnalisée voit sa propriété de texte modifiée. L'étiquette changerait de taille et devrait donc être remesurée et redessinée.
forceLayout()
Lorsqu'il y a un requestLayout()
qui est appelé sur un groupe de vues parent, il n'est pas nécessaire de remesurer et de relayer ses vues enfants. Cependant, si un enfant doit être inclus dans la remesure et le relais, vous pouvez faire appel forceLayout()
à l'enfant. forceLayout()
ne fonctionne sur un enfant que s'il se produit en conjonction avec un requestLayout()
sur son parent direct. L'appel forceLayout()
en lui-même n'aura aucun effet car il ne déclenche pas d' requestLayout()
arborescence de vues.
Lisez ces questions et réponses pour une description plus détaillée de forceLayout()
.
requestLayout()
avant invalidate()
si vous le souhaitez. Ni l'un ni l'autre ne fait de mise en page ou ne dessine immédiatement. Au contraire, ils définissent des drapeaux qui finiront par entraîner un relais et un redessiner.
Ici vous pouvez trouver une réponse: http://developer.android.com/guide/topics/ui/how-android-draws.html
Pour moi, un appel à invalidate()
actualise uniquement la vue et un appel à requestLayout()
actualiser la vue et à calculer la taille de la vue à l'écran.
vous utilisez invalidate () sur une vue que vous souhaitez redessiner, il rendra son onDraw (Canvas c) invoqué, et requestLayout () effectuera à nouveau le rendu de la mise en page (phase de mesure et phase de positionnement). Vous devez l'utiliser si vous modifiez la taille de la vue enfant au moment de l'exécution, mais uniquement dans des cas particuliers comme les contraintes de la vue parent (par là, je veux dire que la hauteur ou la largeur du parent est WRAP_CONTENT et correspond donc à mesurer les enfants avant de pouvoir les envelopper à nouveau)
Cette réponse n'est pas correcte forceLayout()
.
Comme vous pouvez le voir dans le code,forceLayout()
il marque simplement la vue comme "nécessite un relais" mais il ne programme ni ne déclenche ce relais. Le relais ne se produira qu'à un moment donné dans le futur, le parent de la vue a été aménagé pour une autre raison.
Il y a aussi un problème beaucoup plus important lors de l'utilisation forceLayout()
et requestLayout()
:
Disons que vous avez appelé forceLayout()
une vue. Désormais, lors de l'appel requestLayout()
à un descendant de cette vue, Android appellera récursivement requestLayout()
les ancêtres de ce descendant. Le problème est que cela arrêtera la récursion à la vue sur laquelle vous avez appelé forceLayout()
. Ainsi, l' requestLayout()
appel n'atteindra jamais la racine de la vue et ne planifiera donc jamais une passe de mise en page. Un sous-arbre entier de la hiérarchie de vues attend une mise en page et l'appel requestLayout()
sur une vue de ce sous-arbre ne provoquera pas de mise en page. N'appeler que requestLayout()
sur n'importe quelle vue en dehors de ce sous-arbre rompra le charme.
Je considérerais que l'implémentation de forceLayout()
(et comment elle affecte requestLayout()
est cassée et vous ne devriez jamais utiliser cette fonction dans votre code.
View
et en rencontrant le problème moi-même et en le déboguant.
forceLayout()
API: il ne force pas réellement une mise en page, mais change simplement un drapeau qui est observé dansonMeasure()
, mais onMeasure()
ne sera pas appelé à moins requestLayout()
qu'un explicite ne View#measure()
soit appelé. Cela signifie que cela forceLayout()
devrait être associé requestLayout()
. D'un autre côté, pourquoi alors jouer forceLayout()
si j'ai encore besoin de jouer requestLayout()
?
requestLayout()
fait tout ce qui fait forceLayout()
aussi.
forceLayout
sens. Donc, au final, c'est juste très mal nommé et documenté.
invalidate()
---> onDraw()
depuis le fil de l'interface utilisateur
postInvalidate()
---> onDraw()
du fil d'arrière-plan
requestLayout()
---> onMeasure()
et onLayout()
ET PAS nécessairement onDraw()
forceLayout()
---> onMeasure()
et onLayout()
JUST SI le parent direct a appelé requestLayout()
.