• Aucun résultat trouvé

Instanciation des objets XML

Enfin, on peut utiliser cet identifiant dans le code, comme avec les autres identifiants. Pour cela, on utilise la méthode public View findViewById (int id). Attention, cette méthode renvoie une View, il faut donc la « caster » dans le type de destination.

On caste ? Aucune idée de ce que cela peut vouloir dire !

Petit rappel en ce qui concerne la programmation objet : quand une classe Classe_1 hérite (ou dérive, on trouve les deux termes) d'une autre classe Classe_2, il est possible d'obtenir un objet de type Classe_1 à partir d'un de Classe_2 avec le transtypage. Pour dire qu'on convertit une classe mère (Classe_2) en sa classe fille (Classe_1) on dit qu'on caste

Classe_2 en Classe_1, et on le fait avec la syntaxe suivante : Code : Java

//avec « class Class_1 extends Classe_2 » Classe_2 objetDeux = null;

Classe_1 objetUn = (Classe_1) objetDeux;

Ensuite, et c'est là que tout va devenir clair, vous pourrez déclarer que votre activité utilise comme interface graphique la vue que vous désirez à l'aide de la méthode void setContentView (View view). Dans l'exemple suivant, l'interface graphique est référencée par R.layout.activity_main, il s'agit donc du layout d'identifiant main, autrement dit celui que nous avons manipulé un peu plus tôt.

Code : Java

import android.app.Activity; import android.os.Bundle;

import android.widget.TextView;

public class TroimsActivity extends Activity { TextView monTexte = null;

@Override

public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

monTexte = (TextView)findViewById(R.id.text);

monTexte.setText("Le texte de notre TextView"); }

}

Je peux tout à fait modifier le padding a posteriori. Code : Java

import android.app.Activity; import android.os.Bundle;

import android.widget.TextView;

public class TroimsActivity extends Activity { TextView monTexte = null;

@Override

public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

monTexte = (TextView)findViewById(R.id.text);

// N'oubliez pas que cette fonction n'utilise que des entiers

monTexte.setPadding(50, 60, 70, 90);

} }

Y a-t-il une raison pour laquelle on accède à la vue après le setContentView ?

Oui ! Essayez de le faire avant, votre application va planter.

En fait, à chaque fois qu'on récupère un objet depuis un fichier XML dans notre code Java, on procède à une opération qui s'appelle la désérialisation. Concrètement, la désérialisation, c'est transformer un objet qui n'est pas décrit en Java − dans notre cas l'objet est décrit en XML − en un objet Java réel et concret. C'est à cela que sert la fonction View findViewById (int id). Le problème est que cette méthode va aller chercher dans un arbre de vues, qui est créé automatiquement par l'activité. Or, cet arbre ne sera créé qu'après le setContentView ! Donc le findViewById retournera null puisque l'arbre n'existera pas et l'objet ne sera donc pas dans l'arbre. On va à la place utiliser la méthode static View inflate (Context context, int id, ViewGroup parent). Cette méthode va désérialiser l'arbre XML au lieu de l'arbre de vues qui sera créé par l'activité.

Code : Java

import android.app.Activity; import android.os.Bundle;

import android.widget.TextView;

public class TroimsActivity extends Activity { RelativeLayout layout = null;

TextView text = null; @Override

public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

// On récupère notre layout par désérialisation. La méthode inflate retourne un View

// C'est pourquoi on caste (on convertit) le retour de la méthode avec le vrai type de notre layout, c'est-à-dire

RelativeLayout

layout = (RelativeLayout) RelativeLayout.inflate(this, R.layout.activity_main, null);

// … puis on récupère TextView grâce à son identifiant text = (TextView) layout.findViewById(R.id.text);

text.setText("Et cette fois, ça fonctionne !"); setContentView(layout);

// On aurait très bien pu utiliser «

setContentView(R.layout.activity_main) » bien sûr ! }

}

C'est un peu contraignant ! Et si on se contentait de faire un premier setContentView pour « inflater » (désérialiser) l'arbre et récupérer la vue pour la mettre dans un second setContentView ?

Un peu comme cela, voulez-vous dire ? Code : Java

import android.app.Activity; import android.os.Bundle;

import android.widget.TextView;

public class TroimsActivity extends Activity { TextView monTexte = null;

@Override

public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); monTexte = (TextView)findViewById(R.id.text); monTexte.setPadding(50, 60, 70, 90); setContentView(R.layout.activity_main); } }

Ah d'accord, comme cela l'arbre sera inflate et on n'aura pas à utiliser la méthode compliquée vue au-dessus…

C'est une idée… mais je vous répondrais que vous avez oublié l'optimisation ! Un fichier XML est très lourd à parcourir, donc construire un arbre de vues prend du temps et des ressources. À la compilation, si on détecte qu'il y a deux setContentView dans onCreate, eh bien on ne prendra en compte que la dernière ! Ainsi, toutes les instances de setContentView

Eclipse vous permet de confectionner des interfaces à la souris, mais cela ne sera jamais aussi précis que de travailler directement dans le code.

Tous les layouts héritent de la super classe ViewGroup qui elle même hérite de la super classe View. Puisque les widgets héritent aussi de View et que les ViewGroup peuvent contenir des View, les layouts peuvent contenir d'autres layouts et des widgets. C'est là toute la puissance de la hiérarchisation et la confection des interfaces. View regroupe un certain nombre de propriétés qui deviennent communes aux widgets et aux layouts.

Lorsque vous désérialisez (ou inflatez) un layout dans une activité, vous devez récupérer les widgets et les layouts pour lesquels vous désirez rajouter des fonctionnalités. Cela se fait grâce à la classe R.java qui liste l'ensemble des