¿Cómo puedo asignar una ID a una vista mediante programación?

202

En un archivo XML, podemos asignar una ID a una vista como android:id="@+id/something"y luego llamar findViewById(), pero al crear una vista mediante programación, ¿cómo asigno una ID?

Creo que setId()no es lo mismo que la asignación predeterminada. setId()es extra

¿Alguien puede corregirme?

DuyguK
fuente
1
Subconjunto: cómo generar ID únicos: stackoverflow.com/questions/1714297/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respuestas:

521

idResumen de Android

Un Android ides un número entero comúnmente usado para identificar vistas; esto idse puede asignar a través de XML (cuando sea posible) y a través de código (mediante programación). Esto ides más útil para obtener referencias para Views definidos por XML generados por un Inflater(como mediante el uso setContentView).

Asignar idvíaXML

  • Agregue un atributo de android:id="@+id/somename "a su vista.
  • Cuando se compila su aplicación, android:idse le asignará un único int para su uso en el código.
  • Una referencia a su android:id's intvalor en el código usando ' R.id.algunnombre'(efectivamente una constante).
  • esto intpuede cambiar de compilación a compilación, así que nunca copie una identificación de gen/package.name/ R.java, solo use " R.id.somename".
  • (Además, un idasignado a un Preferenceen XML no se usa cuando el Preferencegenera su View.)

Asignar idmediante código (mediante programación)

  • Establecer manualmente ids usando someView.setId(int);
  • El intdebe ser positivo, pero por lo demás arbitrary- puede ser lo que quiera (sigue leyendo si esto es espantoso.)
  • Por ejemplo, si crea y numera varias vistas que representan elementos, puede usar su número de elemento.

Singularidad de ids

  • XML-s asignados idserán únicos.
  • Código asignado ids qué no tienen que ser únicos
  • Los ids asignados por código pueden (en teoría) entrar en conflicto con los s XMLasignados id.
  • Estos ids conflictivos no importan si se consultan correctamente (sigue leyendo) .

Cuando (y por qué) ids conflictivos no importan

  • findViewById(int)iterará primero en profundidad recursivamente a través de la jerarquía de vistas desde la Vista que especifique y devolverá el primero Viewque encuentre con una coincidencia id.
  • Siempre que no haya ningún código asignado idasignado antes de un XML definido iden la jerarquía, findViewById(R.id.somename)siempre devolverá la Vista definida por XML así que id'd.

Crear dinámicamente vistas y asignar IDs

  • En el diseño XML, defina un vacío ViewGroupcon id.
  • Tal como un LinearLayoutcon android:id="@+id/placeholder".
  • Use el código para llenar el marcador de posición ViewGroupcon Views.
  • Si lo necesita o lo desea, asigne los correos idelectrónicos que sean convenientes para cada vista.
  • Consulte estas vistas secundarias utilizando placeholder.findViewById (convenienteInt);

  • Se introdujo la API 17, View.generateViewId()que le permite generar una identificación única.

Si elige mantener referencias a sus vistas , asegúrese de crear instancias con ellas getApplicationContext()y asegúrese de establecer cada referencia como nula onDestroy. Al parecer, se escapa el Activity(suben encima después de que se se destruye) es un desperdicio .. :)

Reserve un XML android:idpara usar en el código

API 17 introducida View.generateViewId() que genera una identificación única. (Gracias a los riesgos de hacer cambios por señalar esto). *

Si ViewGroupno puede definirse a través de XML (o no desea que sea), puede reservar la identificación a través de XML para asegurarse de que siga siendo única:

Aquí, values ​​/ ids.xml define una costumbre id:

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

Luego, una vez que se ha creado ViewGroup o View, puede adjuntar la identificación personalizada

myViewGroup.setId(R.id.reservedNamedId);

idEjemplo conflictivo

Para mayor claridad a modo de ejemplo ofuscante, examinemos lo que sucede cuando hay un idconflicto detrás de escena.

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 un conflicto, digamos que nuestra última compilación asignó R.id.placeholder( @+id/placeholder) un intvalor de 12 ..

A continuación, MyActivity.java define algunas vistas añadidas mediante programación (a través del 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);
}

¡ placeholderY uno de nuestros nuevos TextViews tiene un id12! Pero esto no es realmente un problema si consultamos las vistas secundarias del marcador de posición:

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

*No es tan malo

CodeShane
fuente
9
Además de esto, podría ser útil para alguien en la codificación de soluciones similares estar al tanto de View.generateViewId () en API> 17 para identificadores no conflictivos
AllDayAmazing
Tenga en cuenta que findViewByIdhace una exploración profunda primero, por lo que "siempre y cuando no haya identificadores asignados por código asignados por encima de una identificación definida por XML en la jerarquía" no es técnicamente correcto; es "antes" en lugar de "arriba".
Karu
En las versiones más recientes de las herramientas para desarrolladores de Android, el establecimiento programático de la ID en un valor arbitrario se marcará como un error del compilador. Se espera que el valor sea un ID de recurso real.
ThomasW
Creo que este fue incluso el caso cuando respondí esto hace cinco años, es por eso que la identificación personalizada tuvo que definirse ids.xml. Para identificaciones verdaderamente arbitrarias, use View.generateViewId()(API 17). (Por favor aclare su punto si me lo he perdido.)
CodeShane
> (Además, una identificación asignada a una Preferencia en XML no se usa cuando la Preferencia genera su Vista). Muy interesado en eso. Mi código hereda de PreferenceDialogFragmentCompatél parece que los identificadores de R.idno coinciden con la jerarquía de vistas. De esta manera no puedo encontrar la vista por ID.
UrK
6

Puedes usar el View.setId(integer)para esto. En el XML, aunque esté configurando un ID de cadena, este se convierte en un entero. Debido a esto, puede usar cualquier número entero (positivo) para Views agregar mediante programación.

De acuerdo con la Viewdocumentación

El identificador no tiene que ser único en la jerarquía de esta vista. El identificador debe ser un número positivo.

Por lo tanto, puede usar cualquier número entero positivo que desee, pero en este caso puede haber algunas vistas con id equivalentes. Si desea buscar alguna vista en la jerarquía, puede ser útil llamar a setTag con algunos objetos clave.

Créditos a esta respuesta .

Sander van't Veer
fuente
5

Sí, puede llamar setId(value)en cualquier vista con cualquier valor entero (positivo) que desee y luego encontrarlo en el contenedor principal utilizando findViewById(value). Tenga en cuenta que es válido llamar setId()con el mismo valor para diferentes vistas de hermanos, pero findViewById()solo devolverá la primera.

dmon
fuente
1
Tenga en cuenta que debe usar un número entero mayor que cero.
Peter Ajtai
aunque findViewById (int) iterará recursivamente a través de la jerarquía de vistas desde la Vista que especifique y devolverá la primera Vista que encuentre con una identificación coincidente especificada en la primera respuesta es más precisa.
Aniket Thakur
Sí, llamar findViewByIda un antepasado conocido es una buena idea por razones de rendimiento, pero no garantiza que encontrará un hijo inmediato si hay uno con la identificación correcta.
Karu