Как указать идентификатор при использовании include в XML-файле макета

117

В свой XML-файл макета я включил другой XML-файл макета (каждый с другим идентификатором Android).

<include layout="@layout/view_contact_name" android:id="+id/test1"/>
<include layout="@layout/view_contact_name" android:id="+id/test2"/>

Но когда я запускаю его в эмуляторе и запускаю Hierarchy Viewer, каждый макет по-прежнему показывает «NO_ID», и в моем коде у меня есть findViewById(R.id.test1)и findViewById(R.id.test2)оба возвращают значение null.

Может ли кто-нибудь помочь мне с моей проблемой?

hap497
источник
6
В ваших идентификаторах отсутствует @символ.
AutonomousApps

Ответы:

288

Укажите идентификатор в <include>

<include layout="@layout/test" android:id="@+id/test1" />

Затем используйте два findViewByIdдля доступа к полям в макете

View test1View = findViewById(R.id.test1);
TextView test1TextView = (TextView) test1View.findViewById(R.id.text);

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

Рон Ромеро
источник
18
Этот метод возвращает мне нулевое значение для объекта test1View.
Nirav Shah
4
Я действительно не вижу разницы, вы можете объяснить?
Goddchen
30
Я обнаружил, что если в макете, который мы включили, используется слияние, это не поможет. Но в случае, если слияние не используется, это работает.
Златко
@Zlatko Ага, и это не может работать mergeдаже теоретически, потому что результатом включения mergeявляется не одно представление, а их множество. Так что все нормально.
Отображаемое имя
1
Это будет работать только в том случае, если слияние не используется. В случае слияния это невозможно, как указано здесь: code.google.com/p/android/issues/detail?id=36918#c3
Захид Рашид,
61

Я выяснил, что если вы используете <merge>тег в макете включения, то идентификатор включения передается в тег слияния, который не является реальным представлением.

Так что либо удалите слияние, либо замените его каким-нибудь макетом.

Тор Норбай писал :

<include>Тег не реальный вид, поэтому findByView не найти. Атрибут @id (и любые другие атрибуты, которые вы установили в теге include) вместо этого применяется к корневому тегу включенного макета. Таким образом, ваш activity.getView (R.id.included1) фактически должен быть <TextView>самим собой.

loki19
источник
3
Хороший. Я удаляю тег слияния, и он начинает работать, но мой вопрос заключается в том, как используется тег слияния, если какой-либо макет включает работу без него?
Анкур Чаудхари,
35

Ромен Гай указывает, что вы можете переопределить идентификатор включенного макета, поместив android:idатрибут внутри <include>тега.

<include android:id="@+id/cell1" layout="@layout/workspace_screen" />
Даниэль Янковский
источник
1
Это верно. Способ ссылки на корневой элемент во включенном файле макета - это идентификатор, указанный в теге include (если он не указан).
Tom R
1
ID в <include> = ID корня во включенном макете
Фадилс
Мне кажется, что если я сначала установлю идентификатор (в теге include он переопределяет идентификатор из включенного макета, не так ли?), У меня будет изначально тег включения '@ + id / cell1', а затем layout = ' @ layout / workspace_screen 'снова заменит android: id идентификатором включенного макета. Ответы @Ron Romero имеют для меня больше смысла.
Neon Warge
14

Я думаю, что главный ответ упускает из виду самый важный момент и может ввести людей в заблуждение, думая, что <include/>тег создает представление, содержащее включаемое содержимое.

Ключевой момент является то, что включает в себя'S идентификатор будет принят в корневых зрения включаемого'S файл макет.

Это означает:

// activity_main.xml
<include layout="@layout/somelayout" android:id="@+id/someid"/>

// somelayout.xml
<?xml version="1.0" encoding="utf-8"?>
<ImageView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    />

Становится это:

// activity_main.xml
<ImageView
    android:id="@+id/someid"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    />
Андре Романо
источник
4

Да, это похоже на это, но будьте осторожны, когда макет, вставленный в поле включения, является настраиваемым, и вы хотите получить доступ к этому корневому макету. Этот макет в этом случае @ layout / test test фактически возвращается в первой строке.

test test1View = (test)findViewById(R.id.test1);
jokernk
источник
2
  1. вы должны установить идентификатор для каждого включаемого тега
  2. Включенный дочерний элемент устанавливает новый идентификатор. если вы посмотрите, как сгенерировать новый идентификатор, посмотрите эту запись: https://stackoverflow.com/a/15442898/1136117
Синан Эргин
источник
2

Проблема в том, что мы пытаемся использовать идентификатор, который не объявлен в текущем файле макета. Вместо повторного объявления id можно просто указать с помощью @+id/. Если вы реорганизуете исходное имя идентификатора через Android Studio, оно также выполнит рефакторинг во включенном макете.

<include layout="@layout/toolbar"/>

<TextView
    android:id="@+id/txt_description"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    **android:layout_below="@+id/toolbar"**
    android:layout_marginTop="16dp"
    android:paddingLeft="8dp"
    android:paddingRight="8dp"/>
Пракаш
источник
2

В случае использования <RecyclerView>find id of <include>с помощью экземпляра завышенного представления, иначе он вернет null .

public class ViewHolder extends RecyclerView.ViewHolder {

        private mTextView;

        public ViewHolder(View view) {
            super(view);
            View include_1 = view.findViewById(R.id.include_1);
            mTextView = (TextView) include_1.findViewById(R.id.text_id);
        }
    }
Шанки Бансал
источник
1

Если вы установили id для корневого тега включенного макета, вы можете использовать этот идентификатор или установить id для включенного макета.

Но вы не можете установить id для обоих, это может вызвать исключение.

<include layout="@layout/view_contact_name" android:id="+id/test1"/>

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

....
</LinearLayout>

Или

<include layout="@layout/view_contact_name"/>

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        android:id="@+id/llBottomMainView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

....
</LinearLayout>
Упендра Шах
источник
0

Когда речь идет о включении, у вас либо есть идентификатор в корневом представлении внутри включаемого файла макета, либо в самой строке включения, но не в обоих. Например:

<include layout="@layout/layout1" android:id="@+id/layout1"/>

Макет 1 файл

<RelativeLayout
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/layout2">

</RelativeLayout>

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

mossman252
источник
0

Вау, я не могу поверить, что на этот вопрос пока нет правильного ответа. Это простые теги - отстой. Вы можете изменить только вещи , которые начинаются с android:layout_которых android:idне совпадает. Итак, ответ - вы не можете. Сожалею. Вместо этого вы можете создать класс, который будет ViewGroup, который будет раздувать включенные представления внутри, а затем добавить это как тег в свой макет, но об этом.

TheHebrewHammer
источник