Como posso atribuir um ID a uma exibição programaticamente?

202

Em um arquivo XML, podemos atribuir um ID a uma exibição como android:id="@+id/something"e depois chamar findViewById(), mas, ao criar uma exibição programaticamente, como atribuo uma ID?

Eu acho que setId()não é o mesmo que atribuição padrão. setId()é extra.

Alguém pode me corrigir?

DuyguK
fonte
1
Subconjunto: como gerar identificações exclusivas: stackoverflow.com/questions/1714297/...
Ciro Santilli郝海东冠状病六四事件法轮功

Respostas:

521

idVisão geral do Android

Um Android idé um número inteiro comumente usado para identificar visualizações; isso idpode ser atribuído via XML (quando possível) e via código (programaticamente). idÉ o mais útil para obter referências para Views definidos em XML gerados por um Inflater(como usando setContentView.)

Atribuir idviaXML

  • Adicione um atributo de android:id="@+id/somename "à sua exibição.
  • Quando seu aplicativo é criado, android:idele recebe um exclusivo int para uso em código.
  • Referência seu android:id's intvalor no código usando ' R.id.somename'(efetivamente uma constante.)
  • isso intpode mudar de compilação para compilação, portanto, nunca copie um ID de gen/package.name/ R.java, apenas use " R.id.somename".
  • (Além disso, um idatribuído a um PreferenceXML não é usado quando o Preferencegera View.)

Atribuir idvia código (programaticamente)

  • Defina manualmente ids usando someView.setId(int);
  • O intdeve ser positivo, mas é outra forma arbitrary- ele pode ser o que quiser (continue lendo se isso é terrível.)
  • Por exemplo, se você criar e numerar várias visualizações que representam itens, poderá usar o número do item.

Exclusividade de ids

  • XMLids atribuídos serão únicos.
  • Atribuído pelo Código ids que não tem que ser único
  • idS atribuídos a código podem (teoricamente) entrar em conflito com s XMLatribuídos id.
  • Esses ids conflitantes não importam se consultados corretamente (continue lendo) .

Quando (e por que) conflitos idnão importam

  • findViewById(int)iterará a profundidade primeiro recursivamente através da hierarquia da visualização da Visualização especificada e retornará a primeira Viewencontrada com uma correspondência id.
  • Desde que não haja ids atribuídos por código antes de um XML definido idna hierarquia, findViewById(R.id.somename)sempre retornará a Visualização definida em XML, então id'd.

Criando vistas dinamicamente e atribuindo IDs

  • No XML do layout, defina um vazio ViewGroupcom id.
  • Tal como um LinearLayoutcom android:id="@+id/placeholder".
  • Use o código para preencher o espaço reservado ViewGroupcom Views.
  • Se você precisar ou desejar, atribua quaisquer ids que sejam convenientes para cada visualização.
  • Consulte essas exibições filho usando placeholder.findViewById (convenientInt);

  • Introduzida a API 17, View.generateViewId()que permite gerar um ID exclusivo.

Se você optar por manter as referências às visualizações , instancie-as getApplicationContext()e defina cada referência como nula onDestroy. Aparentemente, vazar o Activity(pendurado nele depois de destruído) é um desperdício .. :)

Reserve um XML android:idpara uso no código

API 17 introduzida View.generateViewId() que gera um ID exclusivo. (Agradecemos a oportunidade de fazer alterações por apontar isso.) *

Se você ViewGroupnão pode ser definido via XML (ou não deseja), você pode reservar o ID via XML para garantir que ele permaneça único:

Aqui, values ​​/ ids.xml define um costume id:

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

Depois que o ViewGroup ou View for criado, você poderá anexar o ID personalizado

myViewGroup.setId(R.id.reservedNamedId);

idExemplo conflitante

Para maior clareza, por exemplo ofuscante, vamos examinar o que acontece quando há um idconflito nos bastidores.

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>

Para simular um conflito, digamos que nossa última compilação tenha atribuído R.id.placeholder( @+id/placeholder) um intvalor de 12 ..

Em seguida, MyActivity.java define algumas visualizações adicionadas programaticamente (via código):

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);
}

Então, placeholdere um dos nossos novos TextViews tem um idde 12! Mas isso não é realmente um problema se consultarmos as visualizações de filhos do espaço reservado:

// 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);

*Não é tão ruim

CodeShane
fonte
9
Além disso, ele pode ser útil para alguém na codificação soluções similiar estar ciente de View.generateViewId () na API> 17 para IDs não conflitantes
AllDayAmazing
Observe que findViewByIda exploração é aprofundada, portanto, "Enquanto não houver IDs atribuídos por código atribuídos acima de um ID definido em XML na hierarquia" não é tecnicamente correto; é "antes" e não "acima".
Karu
Nas versões mais recentes das ferramentas de desenvolvedor do Android, a configuração programada do ID para um valor arbitrário será sinalizada como um erro do compilador. Espera-se que o valor seja um ID de recurso real.
`` #
Acredito que esse foi o caso quando eu respondi isso há cinco anos - é por isso que os IDs personalizados precisam ser definidos em ids.xml . Para IDs verdadeiramente arbitrários, use View.generateViewId()(API 17). (Por favor, esclareça o seu ponto, se eu perdi isso.)
CodeShane
> (Além disso, um ID atribuído a uma Preferência em XML não é usado quando a Preferência gera sua Visualização.) Muito interessado nisso. Meu código herda PreferenceDialogFragmentCompatparece que os IDs de R.idnão correspondem à hierarquia de exibição. Dessa forma, não consigo encontrar a visualização por ID.
Urk
6

Você pode apenas usar o View.setId(integer)para isso. No XML, mesmo que você esteja definindo um ID de String, isso é convertido em um número inteiro. Devido a isso, você pode usar qualquer número inteiro (positivo) para Views adicionar programaticamente.

De acordo com a Viewdocumentação

O identificador não precisa ser exclusivo na hierarquia dessa exibição. O identificador deve ser um número positivo.

Portanto, você pode usar qualquer número inteiro positivo que desejar, mas nesse caso, pode haver algumas visualizações com IDs equivalentes. Se você deseja procurar alguma exibição na hierarquia, chamar a setTag com alguns objetos-chave pode ser útil.

Créditos a esta resposta .

Sander van't Veer
fonte
5

Sim, você pode chamar setId(value)qualquer visualização com qualquer valor inteiro (positivo) que desejar e encontrá-lo no contêiner pai usando findViewById(value). Observe que é válido chamar setId()com o mesmo valor para diferentes visualizações de irmãos, mas findViewById()retornará apenas a primeira.

dmon
fonte
1
Observe que você precisa usar um número inteiro maior que zero.
quer
embora findViewById (int) itere repetidamente através da hierarquia da visualização da Visualização especificada e retorne a primeira Visualização encontrada com um ID correspondente especificado na 1ª resposta é a mais precisa.
Aniket Thakur
Sim, chamar findViewByIdum ancestral conhecido é uma boa ideia por razões de desempenho, mas não garante que ele encontre um filho imediato se houver um com o ID correto.
Karu