Comment attribuer un ID à une vue par programme?

202

Dans un fichier XML, nous pouvons attribuer un ID à une vue similaire android:id="@+id/something", puis appeler findViewById(), mais lors de la création d'une vue par programme, comment attribuer un ID?

Je pense que ce setId()n'est pas la même chose que l'affectation par défaut. setId()est extra.

Quelqu'un peut-il me corriger?

DuyguK
la source
1
Sous-ensemble: comment générer des ID uniques: stackoverflow.com/questions/1714297/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Réponses:

521

idPrésentation d' Android

Un Android idest un entier couramment utilisé pour identifier les vues; cela idpeut être attribué via XML (lorsque cela est possible) et via du code (par programme.) Le idest le plus utile pour obtenir des références pour les Views définis par XML générés par un Inflater(comme en utilisant setContentView.)

Attribuer idviaXML

  • Ajoutez un attribut de android:id="@+id/nom "à votre vue.
  • Lors de la création de votre application, le android:idsera attribué un unique int à utiliser dans le code.
  • Référencez votre android:idde » intla valeur en utilisant le code « R.id.somename »( en fait une constante.)
  • cela intpeut changer de build en build donc ne copiez jamais un id de gen/package.name/ R.java, utilisez simplement " R.id.somename".
  • (En outre, un idaffecté à un Preferencefichier XML n'est pas utilisé lorsque le Preferencegénère son View.)

Attribuer idvia le code (par programme)

  • Définissez manuellement ids à l'aide de someView.setId(int);
  • Le intdoit être positif, mais autrement arbitraire - il peut être ce que vous voulez (continuez à lire si c'est effrayant.)
  • Par exemple, si vous créez et numérotez plusieurs vues représentant des articles, vous pouvez utiliser leur numéro d'article.

Unicité de ids

  • XML-s attribués idseront uniques.
  • Code attribué ids ne pas doivent être uniques
  • Les ids attribués par code peuvent (théoriquement) entrer en conflit avec les s XMLattribués id.
  • Ces ids conflictuels n'auront aucune importance s'ils sont interrogés correctement (continuez à lire) .

Quand (et pourquoi) les conflits idsont sans importance

  • findViewById(int)itérera la profondeur en premier de manière récursive dans la hiérarchie des vues à partir de la vue que vous spécifiez et retournera la première Viewqu'il trouvera avec une correspondance id.
  • Tant qu'il n'y a pas de code idassigné avant un XML défini iddans la hiérarchie, findViewById(R.id.somename)retournera toujours la vue XML définie ainsi id.

Dynamiquement Création de vues et attribuer IDs

  • Dans le format XML, définissez un vide ViewGroupavec id.
  • Comme un LinearLayoutavec android:id="@+id/placeholder".
  • Utilisez du code pour remplir l'espace réservé ViewGroupavec Views.
  • Si vous en avez besoin ou si vous le souhaitez, affectez les ids qui conviennent à chaque vue.
  • Recherchez ces vues enfant à l'aide de placeholder.findViewById (convenientInt);

  • Introduction de l'API 17 View.generateViewId()qui vous permet de générer un ID unique.

Si vous choisissez de conserver les références à vos vues , assurez-vous de les instancier avec getApplicationContext()et assurez-vous de définir chaque référence sur null onDestroy. Apparemment , une fuite de la Activity(agrippent après est détruit) est inutile .. :)

Réserver un XML android:idpour une utilisation dans le code

Introduction de l'API 17 View.generateViewId() qui génère un ID unique. (Merci à take-chances-make-changes de l'avoir signalé.) *

Si votre ViewGroupne peut pas être défini via XML (ou si vous ne le souhaitez pas), vous pouvez réserver l'id via XML pour vous assurer qu'il reste unique:

Ici, values ​​/ ids.xml définit une coutume id:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="reservedNamedId" type="id"/>
</resources>

Ensuite, une fois que le ViewGroup ou la vue a été créé, vous pouvez attacher l'ID personnalisé

myViewGroup.setId(R.id.reservedNamedId);

idExemple contradictoire

Pour plus de clarté, à titre d'exemple d'obscurcissement, examinons ce qui se passe en cas de idconflit dans les coulisses.

layout / mylayout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <LinearLayout
        android:id="@+id/placeholder"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
</LinearLayout>

Pour simuler un conflit, disons que notre dernière version a attribué R.id.placeholder( @+id/placeholder) une intvaleur de 12 ..

Ensuite, MyActivity.java définit certaines vues d'ajout par programme (via le code):

int placeholderId = R.id.placeholder; // placeholderId==12
// returns *placeholder* which has id==12:
ViewGroup placeholder = (ViewGroup)this.findViewById(placeholderId);
for (int i=0; i<20; i++){
    TextView tv = new TextView(this.getApplicationContext());
    // One new TextView will also be assigned an id==12:
    tv.setId(i);
    placeholder.addView(tv);
}

Donc, placeholderet l'un de nos nouveaux TextViews ont tous les deux un idde 12! Mais ce n'est pas vraiment un problème si nous interrogeons les vues enfant de l'espace réservé:

// Will return a generated TextView:
 placeholder.findViewById(12);

// Whereas this will return the ViewGroup *placeholder*;
// as long as its R.id remains 12: 
Activity.this.findViewById(12);

*Pas si mal

CodeShane
la source
9
En plus de cela, il pourrait être utile pour quelqu'un dans le codage de solutions similaires de connaître View.generateViewId () dans l'API> 17 pour les ID non conflictuels
AllDayAmazing
Notez que cela findViewByIdfait une exploration en profondeur, donc "Tant qu'il n'y a pas d'ID assigné par code assigné au-dessus d'un ID défini par XML dans la hiérarchie" n'est pas techniquement correct; c'est "avant" plutôt que "dessus".
Karu
Dans les versions plus récentes des outils de développement Android, la définition par programmation de l'ID sur une valeur arbitraire sera signalée comme une erreur de compilation. La valeur devrait être un ID de ressource réel.
ThomasW
Je pense que c'était même le cas lorsque j'ai répondu il y a cinq ans - c'est pourquoi les identifiants personnalisés devaient être définis dans ids.xml. Pour des ID vraiment arbitraires, utilisez View.generateViewId()(API 17). (Veuillez clarifier votre point si je l'ai manqué.)
CodeShane
> (De plus, un identifiant attribué à une préférence en XML n'est pas utilisé lorsque la préférence génère sa vue.) Très intéressé par cela. Mon code en hérite PreferenceDialogFragmentCompatsemble que les identifiants de R.idne correspondent pas à la hiérarchie des vues. De cette façon, je ne trouve pas la vue par ID.
UrK
6

Vous pouvez simplement utiliser le View.setId(integer)pour cela. Dans le XML, même si vous définissez un identifiant de chaîne, celui-ci est converti en entier. Pour cette raison, vous pouvez utiliser n'importe quel entier (positif) pour l' Views ajouter par programme.

Selon la Viewdocumentation

L'identifiant n'a pas besoin d'être unique dans la hiérarchie de cette vue. L'identifiant doit être un nombre positif.

Vous pouvez donc utiliser n'importe quel entier positif que vous aimez, mais dans ce cas, il peut y avoir des vues avec des identifiants équivalents. Si vous souhaitez rechercher une vue dans la hiérarchie, appeler setTag avec certains objets clés peut être pratique.

Crédits à cette réponse .

Sander van't Veer
la source
5

Oui, vous pouvez appeler setId(value)dans n'importe quelle vue avec n'importe quelle valeur entière (positive) que vous aimez, puis la trouver dans le conteneur parent en utilisant findViewById(value). Notez qu'il est valide d'appeler setId()avec la même valeur pour différentes vues de frère, mais findViewById()ne renverra que la première.

dmon
la source
1
Notez que vous devez utiliser un entier supérieur à zéro.
Peter Ajtai
bien que findViewById (int) répète de manière récursive la hiérarchie des vues à partir de la vue que vous spécifiez et renvoie la première vue qu'il trouve avec un identifiant correspondant spécifié dans la première réponse est le plus précis.
Aniket Thakur
Oui, faire appel findViewByIdà un ancêtre connu est une bonne idée pour des raisons de performances, mais cela ne garantit pas qu'il trouvera un enfant immédiat s'il y en a un avec l'ID correct.
Karu