2011-09-15 2 views
6

J'écris une application dans le seul but d'essayer de comprendre comment fonctionne la hiérarchie des vues dans Android. J'ai des problèmes vraiment sérieux en ce moment. Je vais essayer d'être concis dans mes explications ici.Essayer de comprendre la hiérarchie des vues

Configuration:

Actuellement, j'ai trois vues. 2 sont ViewGroups et 1 est juste un View. Disons qu'ils sont dans cet ordre:

TestA extends ViewGroup 
    TestB extends ViewGroup 
    TestC extends View 
    TestA->TestB->TestC 
    Where TestC is in TestB and TestB is in TestA. 

Dans mon Activity j'afficher simplement les vues comme ceci:

TestA myView = new TestA(context); 
myView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT)); 
setContentView(myView); 

Problèmes:

  1. La méthode onDraw(Canvas canvas) de TESTA jamais appelé. J'ai vu quelques solutions à cela en disant que ma vue n'a pas de dimensions (height/width = 0), cependant, ce n'est pas le cas. Lorsque je remplace onLayout(), j'obtiens les dimensions de ma mise en page et elles sont correctes. De plus, getHeight()/Width() est exactement ce qu'il devrait être. Je peux également remplacer dispatchDraw() et obtenir mes vues de base pour se dessiner.

  2. Je souhaite animer un objet dans TestB. Traditionnellement, je remplacerait la méthode onDraw() sur l'appel invalidate() sur lui-même jusqu'à ce que l'objet finisse l'animation qu'il était censé faire. Cependant, dans TestB, quand j'appelle invalidate() la vue ne se redessine jamais. Je suis sous l'impression que c'est le travail de ma vue parente d'appeler à nouveau la méthode onDraw(), mais ma vue parente n'appelle pas encore le dispatchDraw().

Je suppose que mes questions sont, pourquoi ma méthode onDraw() de mon point de vue des parents ne sont jamais appelés à commencer? Quelles sont les méthodes dans la vue de mes parents qui sont censées être appelées quand l'un de ses enfants s'invalide? Est-ce que le parent est responsable de s'assurer que les enfants sont attirés ou qu'Android s'en occupe-t-il? Si Android répond à invalidate(), pourquoi mon TestB ne sera plus jamais dessiné?

Répondre

5

Ok, après quelques recherches et beaucoup d'essais, j'ai découvert que je faisais trois choses mal en ce qui concerne le problème n ° 2. Beaucoup de réponses étaient simples mais pas très évidentes.

  • Pour chaque vue, vous devez remplacer onMeasure(). Au onMeasure(), vous devez appeler measure() pour chaque enfant contenu dans le ViewGroup en passant dans le MeasureSpec dont l'enfant a besoin.

  • Vous devez appeler addView() pour chaque enfant que vous voulez inclure. A l'origine, j'ai simplement créé un objet vue et je l'ai utilisé directement.Cela m'a permis de le dessiner une fois, mais la vue n'était pas incluse dans l'arbre de vue, donc quand j'ai appelé invalidate() cela n'invalidait pas l'arbre de vue et ne le redessinait pas. Par exemple:

En TESTA:

TestB childView; 
TestA(Context context){ 
    ****** setup code ******* 
    LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 
    childView = new TestB(context); 
    childView.setLayoutParams(params); 
} 

@Override 
protected void dispatchDraw(Canvas canvas){ 
    childView.draw(canvas); 
} 

Cela attirera une fois la vue des enfants. Cependant, si cette vue a besoin d'être mise à jour pour des animations ou autre, c'est tout. J'ai mis addView(childView) dans le constructeur de TestA pour l'ajouter à l'arbre de vue. Code final est en tant que tel:

TestB childView; 
TestA(Context context){ 
    ****** setup code ******* 
    LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 
    childView = new TestB(context); 
    childView.setLayoutParams(params); 
    addView(childView); 
} 

@Override 
protected void dispatchDraw(Canvas canvas){ 
    childView.draw(canvas); 
} 

Sinon, je pourrais passer outre dispatchDraw(Canvas canvas) comme si j'avais beaucoup plus d'enfants à dessiner, mais je dois un élément personnalisé entre chaque dessin comme des lignes de la grille ou quelque chose.

@Override 
protectd void dispatchDraw(Canvas canvas){ 
    int childCount = getChildCount(); 
    for(int i = 0; i < size; i++) 
    { 
     drawCustomElement(); 
     getChildAt(i).draw(canvas); 
    } 
} 
  • Vous devez remplacer onLayout() (il est résumé en ViewGroup de toute façon, il est donc nécessaire de toute façon). Dans cette méthode, vous devez appeler layout pour chaque enfant. Même après avoir fait les deux premières choses, mon point de vue ne serait pas invalide. Dès que j'ai fait ça, tout a parfaitement fonctionné.

MISE À JOUR: Problème n ° 1 a été résolu. Une autre solution extrêmement simple mais pas si évidente.

Lorsque je crée une instance de TestA, je dois appeler le setWillNotDraw(false) sinon Android ne le dessinera pas pour des raisons d'optimisation. Donc, la configuration complète est:

TestA myView = new TestA(context); 
myView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT)); 
myView.setWillNotDraw(false); 
setContentView(myView); 
+0

pouvez-vous partager ce projet de démonstration du Viewgroup dans votre blog ou quelque part il sera très utile .. Merci compagnon .. – user1201239

+0

dois-je ajouter le childView même si nous le spécifions en XML? – user1201239

+0

Je suis désolé. Je n'ai pas de blog ou quoi que ce soit à télécharger. Je vais essayer d'être aussi utile que possible. Pour répondre à votre première question, non. Lorsque vous gonflez le fichier XML, l'enfant est contenu dans 'ViewGroup'. Le plus tôt vous pouvez le récupérer est 'onFinishInflate()'. Après cela, vous avez le choix. Soit obtenir vos enfants via la méthode 'getChildAt (int index)' ou utiliser 'findViewById (int id)'. L'index sera l'ordre dans lequel les enfants sont situés dans XML. Je ne sais pas comment fonctionne l'indexation avec les enfants au sein des enfants. – DeeV

2

Ce n'est pas une réponse directe, mais here is a fantastic tutorial sur la façon de dessiner des vues personnalisées et donne un cours intensif dans la façon d'animer une vue. Le code est très simple et propre aussi.

Espérons que cela aide!

+0

Merci. Cela n'a pas résolu mes problèmes, mais cela m'a aidé à trouver une solution. – DeeV

Questions connexes