NavigationView получить / найти макет заголовка

171

В моем NavigationView у меня есть макет заголовка с идентификатором 'viewId' с активными кнопками. Чтобы настроить эти кнопки, я делаю следующее в действиях onPostCreate:

final View panel = findViewById(R.id.viewId);
panel.setOnClickListener(new View.OnClickListener() {
... setup goes here ...
});

С новой версией библиотеки поддержки Android ( 23.1.0 ) представление не может быть найдено, оно возвращает ноль. С предыдущими версиями это работало хорошо. Это ошибка или я использую эту функцию неправильно? Если так, как получить доступ к макету заголовка и добавить к нему поведение?

Хусрав
источник

Ответы:

429

Версия 23.1.0 переключается NavigationViewна использование RecyclerView(а не предыдущий ListView) и заголовок добавляется в качестве одного из этих элементов. Это означает, что он не доступен мгновенно для вызова findViewById()- перед тем, как присоединить его к, требуется проход макета NavigationView.

Для версии 23.1.1 библиотеки поддержки теперь вы можете получить ссылку на представление заголовка, используя getHeaderView():

View headerLayout = navigationView.getHeaderView(0); // 0-index header

Это имеет преимущество работы с заголовками, добавленными через XML и через код.

Если вы по-прежнему используете 23.1.0, согласно соответствующей ошибке , вы можете надуть заголовок в коде и использовать его findViewById():

View headerLayout = 
    navigationView.inflateHeaderView(R.layout.navigation_header);
panel = headerLayout.findViewById(R.id.viewId);
// panel won't be null

Пока вы не перейдете к 23.1.1.

ianhanniballake
источник
1
Спасибо за оперативную помощь, буду использовать обходной путь. Выделенный метод кажется правильным, надеюсь, он будет в следующих выпусках.
хусрав
2
@AlexanderFarber - код, который я разместил, работает с API 7
ianhanniballake
4
Я предпочитаю понизить libs. Представление ошибки похоже на подпись от Google. Если в новой версии есть ошибка, то Google выпустит эту новую версию
BamsBamx
1
@GFPF - когда вы звоните inflateHeaderView, он присоединяет View для вас в правильном слое в RecyclerViewс правильным родителем - что вы не можете сделать внешне NavigationView.
ianhanniballake
1
@RmK - спасибо, я обновил ответ, чтобы отразить новые API, добавленные в 23.1.1 для извлечения заголовков, добавленных через XML (так как предыдущий обходной путь работал только для заголовков, добавленных через код).
Ianhanniballake
142

Теперь, с выпуском 23.1.1 библиотеки поддержки проектирования, вы можете использовать

NavigationView navigationView = (NavigationView) findViewById(R.id.your_nav_view_id);
View header = navigationView.getHeaderView(0)
TextView text = (TextView) header.findViewById(R.id.textView);
Франсуа Дерму
источник
Вы также можете использовать, navigationView.getHeaderCount()если у вас есть более 1 заголовка по любой причине.
Франсуа Дерму
13

Вот как я сделал это с помощью, ButterKnifeи это работает для меня.

protected static class HeaderViewHolder {

    @BindView(R.id.button)
    Button button;

    HeaderViewHolder(View view) {
        ButterKnife.bind(this, view);
    }
}

и затем используйте этот держатель вида следующим образом:

View header = navigationView.getHeaderView(0);
headerViewHolder = new HeaderViewHolder(header);
Вахиб Ул Хак
источник
2
Это идеально, если вы хотите удалить логику, связанную с просмотром, из вашей активности. Отличная идея!
17
2
Отлично работает с ButterKnife, спасибо брат.
Раджеш Надди
8

Для меня это была та же самая ситуация с 23.1.0, после обновления исключение нулевого указателя стало. В этом случае NavigatorViewвыглядит так:

<android.support.design.widget.NavigationView
  android:id="@+id/navigation_view"
  android:layout_height="match_parent"
  android:layout_width="wrap_content"
  android:layout_gravity="start"
  android:fitsSystemWindows="true"
  app:headerLayout="@layout/nav_header"
  app:menu="@menu/menu_nav"/>

Я попробовал предложение ianhanniballake, но оно не работает. Тогда я надулся с предложением:

LayoutInflater.from(getContext()).inflate(R.layout.nav_header, mNavigationView);

После этого я могу найти по id все виды, определенные в nav_heardмакете.

Кампино
источник
3
NavigationView navigationView = findViewById(R.id.your_nav_view);
View header = navigationView.getHeaderView(0);
TextView textUsername = header.findViewById(R.id.textView);
textUsername.setText("you text here ");
Индрит Савета
источник
Здравствуйте и добро пожаловать в Stack Overflow! Пожалуйста, добавьте текст, объясняющий, как это решает вопрос, заданный выше. Спасибо!
Джонатан
0

В Kotlin @Francois Dermu код будет как

val navigationView : NavigationView = findViewById(R.id.your_nav_view_id);
val header = navigationView.getHeaderView(0)
val textView = header.findViewById<TextView>(R.id.textView)
Alex
источник
0

Котлин версия.

val navView: NavigationView = findViewById(R.id.nav_view)       
// set User Name
val headerView: View = navView.getHeaderView(0)
headerView.txtUserName.text = "User Name Goes here"
Кадир Хуссейн
источник