Как программно назначить идентификатор для представления?

202

В XML-файле мы можем назначить идентификатор для подобного представления, android:id="@+id/something"а затем вызвать findViewById(), но как программно создать представление, как назначить идентификатор?

Я думаю, что setId()это не то же самое, что назначение по умолчанию. setId()это дополнительно.

Кто-нибудь может меня поправить?

DuyguK
источник
1
Подмножество: как сгенерировать уникальные идентификаторы: stackoverflow.com/questions/1714297/…
Сиро Сантилли 16 冠状 病 六四 事件 法轮功

Ответы:

521

idОбзор Android

Android id- это целое число, обычно используемое для идентификации представлений; это idможет быть назначено через XML (когда это возможно) и через код (программно.). Это idнаиболее полезно для получения ссылок на определенные XML-данные, Viewсгенерированные Inflater(например, с помощью setContentView.)

Назначить idчерезXML

  • Добавьте атрибут android:id="@+id/somename "к вашему представлению.
  • Когда ваше приложение будет создано, android:idему будет присвоен уникальный int код для использования в коде.
  • Ссылочная свой android:id«сек intзначения в коде с помощью„ R.id.SomeName“(фактически константы) .
  • это intможет измениться от сборки к сборке, поэтому никогда не копируйте идентификатор из gen/package.name/ R.java, просто используйте « R.id.somename».
  • (Кроме того, idприсвоение Preferenceв XML не используется, когда Preferenceгенерирует его View.)

Назначить idчерез код (программно)

  • Вручную установите idс использованием someView.setId(int);
  • intДолжен быть положительным, но в противном случае arbitrary- это может быть все , что вы хотите (продолжайте читать , если это страшно.)
  • Например, при создании и нумерации нескольких представлений, представляющих элементы, вы можете использовать их номер элемента.

Уникальность idс

  • XMLназначенный ids будет уникальным.
  • Код , назначенный idей ничего не должны быть уникальными
  • Назначенный код ids может (теоретически) конфликтовать с XML-assigned ids.
  • Эти конфликтующие ids не будут иметь значения, если их правильно запросить (продолжайте читать) .

Когда (и почему) конфликтующие ids не имеют значения

  • findViewById(int)будет рекурсивно выполнять итерацию в глубину по иерархии представления из указанного вами представления и возвращать первое Viewнайденное совпадение id.
  • До тех пор, пока в иерархии, idопределенной idв XML , нет назначенных кодов , findViewById(R.id.somename)они всегда будут возвращать вид, определенный в XML, так что id'd.

Динамически Создание представлений и назначая IDсек

  • В макете XML определите пустое значение ViewGroupс id.
  • Такие как LinearLayoutс android:id="@+id/placeholder".
  • Используйте код для заполнения заполнителя ViewGroupс Viewс.
  • Если вам нужно или хотите, назначьте любые ids, которые удобны для каждого представления.
  • Запросите эти дочерние представления, используя placeholder.findViewById (cozyInt);

  • Введен API 17, View.generateViewId()который позволяет генерировать уникальный идентификатор.

Если вы решите хранить ссылки на свои представления , обязательно создайте для них экземпляр getApplicationContext()и обязательно установите для каждой ссылки значение null in onDestroy. Видимо утечки на Activity(висит на это после того, как уничтожается) расточительно .. :)

Зарезервируйте XML android:idдля использования в коде

API 17 представил, View.generateViewId() который генерирует уникальный идентификатор. (Спасибо take-chances-make-changes за указание на это.) *

Если ваш ViewGroupне может быть определен с помощью XML (или вы не хотите, чтобы он был), вы можете зарезервировать идентификатор с помощью XML, чтобы убедиться, что он остается уникальным:

Здесь values ​​/ ids.xml определяет пользовательский id:

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

Затем, когда ViewGroup или View были созданы, вы можете прикрепить пользовательский идентификатор

myViewGroup.setId(R.id.reservedNamedId);

Противоречивый idпример

Для ясности на примере запутывания давайте рассмотрим, что происходит, когда idза кадром возникает конфликт.

макет / 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>

Для имитации конфликта, скажем, наша последняя сборка assign R.id.placeholder( @+id/placeholder) имеет intзначение 12 ..

Далее, MyActivity.java определяет некоторые добавления представления программно (через код):

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

Таким образом, placeholderи у одного из наших новых TextViewесть id12! Но на самом деле это не проблема, если мы запросим дочерние представления заполнителя:

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

*Не так уж и плохо

CodeShane
источник
9
В дополнение к этому, кому-то, кто разрабатывает аналогичные решения, может быть полезно знать о View.generateViewId () в API> 17 для неконфликтующих идентификаторов
AllDayAmazing
Обратите внимание, что findViewByIdвыполняется исследование в глубину, поэтому «Пока нет идентификаторов, назначенных коду, назначенных над идентификатором, определенным в XML в иерархии», это технически неверно; это «до», а не «выше».
Кару
В более поздних версиях инструментов разработчика Android программная установка произвольного значения идентификатора будет помечена как ошибка компилятора. Ожидается, что значение будет фактическим идентификатором ресурса.
ThomasW
Я полагаю, что это был даже тот случай, когда я ответил на это пять лет назад - вот почему пользовательский идентификатор должен быть определен в ids.xml. Для действительно произвольных идентификаторов используйте View.generateViewId()(API 17). (Пожалуйста, уточните свою точку зрения, если я пропустил это.)
CodeShane
> (Кроме того, идентификатор, назначенный предпочтению в XML, не используется, когда предпочтение создает его представление.) Это очень интересно. Мой код наследует от PreferenceDialogFragmentCompatнего, кажется, идентификаторы из R.idне соответствуют иерархии представления. Таким образом, я не могу найти вид по ID.
UrK
6

Вы можете просто использовать View.setId(integer)для этого. В XML, даже если вы устанавливаете идентификатор String, он преобразуется в целое число. В связи с этим вы можете использовать любое (положительное) целое число для программного Views добавления.

Согласно Viewдокументации

Идентификатор не обязательно должен быть уникальным в иерархии этого представления. Идентификатор должен быть положительным числом.

Таким образом, вы можете использовать любое положительное целое число, которое вам нравится, но в этом случае могут быть некоторые представления с эквивалентными идентификаторами. Если вы хотите найти какое-то представление в иерархии, может пригодиться вызов setTag с некоторыми ключевыми объектами.

Кредиты на этот ответ .

Sander van't Veer
источник
5

Да, вы можете вызвать setId(value)любое представление с любым (положительным) целочисленным значением и затем найти его в родительском контейнере, используя findViewById(value). Обратите внимание, что допустимо вызывать setId()с одним и тем же значением для разных одноуровневых представлений, но findViewById()вернет только первое.

DMON
источник
1
Обратите внимание, что вы должны использовать целое число больше нуля.
Питер Айтай
хотя findViewById (int) будет рекурсивно выполнять итерацию по иерархии представлений из указанного вами представления и возвращать первое найденное представление с совпадающим идентификатором, указанным в 1-м ответе, является наиболее точным.
Аникет Тхакур
Да, вызов findViewByIdизвестного предка является хорошей идеей из соображений производительности, но он не гарантирует, что он найдет ближайшего ребенка, если есть ребенок с правильным ID.
Кару