NavigationView onClick из xml вызывает ошибки

Используя NavigationView из недавно выпущенной библиотеки дизайна поддержки Android, если макет заголовка навигации включает onClick (в xml), событие onClick приводит к сбою приложения. OnClick можно добавить программно через view.onClickListener (вместо xml), и тогда щелчок работает нормально. Но по какой-то причине всякий раз, когда используется xml onClick, возникает ошибка.

Вот мой основной макет:

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/mainActivityLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <RelativeLayout
        android:id="@+id/mainContentFrame"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        ...

    </RelativeLayout>

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

    </android.support.design.widget.NavigationView>

</android.support.v4.widget.DrawerLayout>

В моей деятельности щелчки моего пункта меню (добавленные с помощью navView.setNavigationItemSelectedListener()) работают нормально. Проблема заключается в том, что при нажатии на заголовок:

ящик_заголовок.xml:

...

<View
    android:id="@+id/testButton"
    android:layout_width="match_parent"
    android:layout_height="60dp"
    android:onClick="testButtonClick"/>

...

Выдает следующую ошибку:

java.lang.IllegalStateException: Could not find a method testButtonClick(View) 
in the activity class android.view.ContextThemeWrapper for onClick handler
on view class android.view.View with id 'testButton'

ОБНОВЛЕНИЕ

NavigationView может использовать стандартные файлы ресурсов меню, но возникает аналогичная проблема при использовании onClick из XML-ресурса меню. Согласно справке по ресурсам меню, атрибут android:onClick переопределяет обычный обратные вызовы. Обычно это работает нормально, но с элементами меню в NavigationView это не так. Вместо этого он вылетает с этой ошибкой:

java.lang.RuntimeException: Unable to start activity ComponentInfo{...}:
android.view.InflateException: Binary XML file line #34: 
Error inflating class android.support.design.widget.NavigationView

Ошибка исчезает, когда я удаляю XML onClick.

ОБНОВЛЕНИЕ

Я протестировал xml onClick, используя «официальный» демонстрационный проект для Android Design Library. Те же результаты: добавление onClick (в xml) в меню или заголовок NavigationView приводит к сбою приложения. Так что это похоже на ошибку с NavigationView.

РЕШЕНО В версии 23.1

Компания Google выпустила исправление для этих ошибок XML onClick в Support Library v23. .1.


person hungryghost    schedule 31.05.2015    source источник
comment
ты используешь фрагменты   -  person Elltz    schedule 31.05.2015
comment
Да, я использую фрагменты и просмотрщик.   -  person hungryghost    schedule 31.05.2015
comment
хорошо, так что onclick в xml не будет работать в действии, потому что представление заголовка живет в классе фрагментов, имеет ли это смысл, сэр?   -  person Elltz    schedule 31.05.2015
comment
Я не понимаю, что ты говоришь. Я использую viewpager и фрагменты, но только в своей основной области содержимого, а не в моем ящике. Мое представление заголовка добавляется через XML в новый виджет NavigationView. Этот заголовок — просто еще один XML-файл макета. Я что-то упускаю?   -  person hungryghost    schedule 31.05.2015
comment
Возможно, это сделает @Elltz слова яснее.   -  person Simas    schedule 31.05.2015
comment
@Simas, спасибо за ссылку, но это onClick не из фрагмента. Это из NavigationView в Activity.   -  person hungryghost    schedule 31.05.2015
comment
Вы должны использовать OnNavigationItemSelectedListener. Потому что это правильно, чисто, просто и позволяет легко расширять и модифицировать код. Что касается проблемы, вы должны опубликовать всю трассировку стека. Мы можем посмотреть исходный код, чтобы получить некоторые подсказки или, скорее всего, решить эту проблему.   -  person    schedule 19.06.2015


Ответы (4)


Подтверждено, это ошибка в библиотеке поддержки.

Очевидно, это связано с ContextThemeWrapper, и согласно этому отчету об ошибке , проблема существует в библиотеке поддержки 22.1.

Короткий ответ:

Не используйте XML onClick с NavigationView (или некоторыми другими компонентами, такими как EditText), пока это не будет исправлено.

Временное решение:

Установите прослушиватели кликов в коде. Для NavigationView используйте setNavigationItemSelectedListener().

ОБНОВЛЕНИЕ: эта ошибка исправлена

Теперь вы можете использовать XML onClick в библиотеке поддержки 23.1 (отчет об ошибке). Я проверил, что это работает в моем приложении. Но, кажется, есть другие (более новые) проблемы XML с NavView в версии 23.1 (см. ниже), хотя эта конкретная ошибка onClick теперь исправлена.

Для полноты:

Кажется, есть еще одна (связанная?) ошибка при раздувании заголовка NavigationView через XML. Использование XML app:headerLayout приводит к ошибкам с 23.1, хотя XML onClick теперь работает. Из-за этой проблемы с инфляцией вам нужно будет использовать метод NavigationView.inflateHeaderView() в коде. Этот новый метод был добавлен в 23.1, и, по-видимому, предыдущее наполнение XML теперь сломано (или, может быть, они устарели app:headerLayout, никому не сказав?). Подробнее см. здесь.

person hungryghost    schedule 05.06.2015
comment
Я реализовал случай переключения в setNavigationItemSelected..(). открывать различные фрагменты. Он хорошо работает для макета телефона, но при макете с двумя панелями тот же код не работает. срабатывает случай по умолчанию. это означает, что идентификаторы для MenuItem изменились. - person Y2K; 14.09.2015

Привет: мое решение удалить

app:headerLayout="@layout/drawer_header"

из вашего макета NavigationView, как показано ниже:

<android.support.design.widget.NavigationView
    android:id="@+id/drawerNavView"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:fitsSystemWindows="true"
    app:menu="@menu/drawer_menu">
</android.support.design.widget.NavigationView>

А затем используйте ниже в своей деятельности или контроллере просмотра

NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
View headerView= navigationView.inflateHeaderView(R.layout.nav_header);

TextView tvName = (TextView) headerView.findViewById(R.id.id_nav_header_uname);
tvName.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        L.d("=======tv click=====");
    }
});

это работает для меня.

person Summer    schedule 22.10.2015
comment
Извини. Как я уже говорил в своем исходном посте, мы, очевидно, можем добавить onClick в Java. Ошибка в том, что onClick не работал с XML. В любом случае, этот вопрос сейчас спорный, так как Google выпустила исправление ошибки. Смотрите мой обновленный пост для информации. - person hungryghost; 23.10.2015
comment
Я видел ошибку, исправленную Google, я использую библиотеку поддержки 23.1, но она не может добавить onClick, если вы не используете navigationView.inflateHeaderView(R.layout.nav_header); для загрузки представления. через xml нельзя установить onClick в NavigationView для headerView. - person Summer; 23.10.2015
comment
Похоже, это еще одна ошибка с раздуванием заголовка NavigationView через XML. У меня была такая же проблема с v23.1, но XML onClick теперь работает нормально (я проверил в своем приложении). Просто теперь XML app:headerLayout не работает, поэтому вы вынуждены использовать inflateHeaderView() в коде. Этот метод был только что добавлен в 23.1, поэтому похоже, что они что-то сломали в реализации. Шаг вперед, шаг назад. Я искал информацию об этой проблеме XML app:headerLayout на прошлой неделе, но ничего не нашел. Может быть, вы хотите опубликовать новый вопрос для него? - person hungryghost; 23.10.2015
comment
О, похоже, что другие люди уже писали об этой проблеме с надуванием с тех пор, как я последний раз смотрел. stackoverflow.com/a/33163288/3449044 - person hungryghost; 23.10.2015

Вы можете написать свой метод в коде, не упоминая его в XML. В коде вы просто используете код

public void methodName()
{
//
}

View v = findViewById(R.id.view_id);
v.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
methodName();
}
});
person Vendetta8247    schedule 31.05.2015
comment
Я знаю, что могу добавить onClickListener, и это то, что я уже делаю, чтобы обойти эту проблему. Мне интересно, почему XML onClick не работает. Я думаю, что это может быть ошибка с новой библиотекой поддержки. - person hungryghost; 31.05.2015
comment
@hungryghost, если честно, я никогда особо не вникал в это, пока способ кодирования выглядит для меня красивее, и он просто работает. Но я буду следить за этим постом на всякий случай, если я узнаю что-то интересное. - person Vendetta8247; 31.05.2015
comment
Кодирование работает нормально и достаточно просто. Но в моей конкретной реализации я на самом деле собираюсь выполнять более сложную замену макетов и тому подобное, и XML onClick немного упростит эту задачу. Но это действительно не по делу. Для меня я просто удивлен этой ошибкой. Я понятия не имею, почему это не сработает. Кроме того, мне, вероятно, следует изменить свой вопрос, чтобы было более понятно, о чем я спрашиваю. У меня такое чувство, что я получу намного больше, просто используя ответы OnClickLIstener, если я не буду более явным! - person hungryghost; 31.05.2015
comment
@hungryghost, кстати, извините, что ответил. Это должен был быть комментарий. У меня просто нет 50 репутации, и если это могло помочь, я должен был ответить - person Vendetta8247; 31.05.2015
comment
о нет проблем. Это хорошо, что ты сделал это ответом. Я бы отметил это как правильное, но это не совсем то, о чем я спрашивал. Я отредактировал свой первоначальный вопрос, чтобы было понятнее, о чем я говорю. Удачи получить эти 50 повторений. Я проголосую за ваш комментарий, чтобы помочь. Почти готово! - person hungryghost; 31.05.2015

NavigationView имеет OnNavigationItemSelectedListener для пунктов меню.

e.g.

navigationView.setNavigationItemSelectedListener(new SelectedNavigationItemListener());

private class SelectedNavigationItemListener implements NavigationView.OnNavigationItemSelectedListener {

    @Override
    public boolean onNavigationItemSelected(MenuItem menuItem) {

        switch (menuItem.getItemId()){
            case id1:
                break;
        }

        Log.d("MENU ITEM", menuItem.getTitle().toString());
        return false;
    }

}

Для заголовка вы можете сделать что-то вроде этого, например

navigationView = (NavigationView) findViewById(R.id.navigation_view);
View header = navigationView.inflateHeaderView(R.layout.drawer_header);
RelativeLayout drawerHeader = (RelativeLayout) header.findViewById(R.id.drawerHeader);
drawerHeader.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Log.d("CLICKED HEADER", "Header Clicked");
    }
});

Ссылка для моего HeaderLayout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawerHeader"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="12dp">

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/app_name"
    android:textSize="16sp" />

person Hiroga Katageri    schedule 04.06.2015
comment
Извините, я думаю, вы неправильно поняли вопрос. Я не спрашиваю, как добавить прослушиватель кликов в код. Мой вопрос в том, почему возникает ошибка с xml onClick. Я почти уверен, что это ошибка в библиотеке. - person hungryghost; 04.06.2015