4

Using NavigationView from the newly released Android support design library, if a navigation header layout includes an onClick (in the xml), onClick event crashes app. OnClick can be added programmatically via view.onClickListener (instead of xml), and then clicking works fine. But for some reason, whenever xml onClick is used, there is an error.

Here's my main layout:

<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>

In my activity, my menu item clicks (added with navView.setNavigationItemSelectedListener()) work fine. The problem is when the header is clicked:

drawer_header.xml:

...

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

...

Produces the following error:

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'

UPDATE

NavigationView can use standard Menu resource files, but there is a similar problem if using onClick from the menu XML resource. According to the Menu Resource reference, the android:onClick attribute overrides the normal callbacks. This usually works fine, but with menu items in NavigationView, it doesn't. Instead, it crashes with this error:

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

The error goes away when I remove the XML onClick.

UPDATE

I tested xml onClick using the "official" demo project for the Android Design Library. Same results: adding onClick (in xml) to a NavigationView's menu or header causes the app the crash. So this appears to be a bug with NavigationView.

RESOLVED IN v23.1

Google released a fix for these XML onClick errors in Support Library v23.1.

hungryghost
  • 9,463
  • 3
  • 23
  • 36
  • are you using fragments – Elltz May 31 '15 at 02:47
  • Yes, I'm using fragments and a viewpager. – hungryghost May 31 '15 at 02:49
  • well so onclick in xml would not work in the activity because because the header view lives in a fragment class, does it make sense sir? – Elltz May 31 '15 at 02:51
  • I don't understand what you're saying. I'm using viewpager and fragments, but only in my main content area, not within my drawer. My header view is added via XML to the new NavigationView widget. That header is simply another XML layout file. Am I missing something? – hungryghost May 31 '15 at 02:59
  • 1
    Maybe [this](http://stackoverflow.com/questions/6091194/how-to-handle-button-clicks-using-the-xml-onclick-within-fragments) will make @Elltz words clearer. – Simas May 31 '15 at 05:53
  • @Simas, thanks for the link, but this onClick is not from a Fragment. It's from a NavigationView in an Activity. – hungryghost May 31 '15 at 05:56
  • You should use OnNavigationItemSelectedListener. Because Its correct, clean, simple and allows easy code expansion and modification. Regarding the problem you should post the whole stacktrace. We can look at the source code to get some hints or most probably solve it. –  Jun 19 '15 at 08:37

4 Answers4

2

Confirmed, this is a bug in the support library.

Apparently it's related to ContextThemeWrapper, and according to this bug report, the problem exists in Support Library 22.1.

So, the short answer is:

Don't use XML onClick with NavigationView (or some other components like EditText), until it's fixed.

Workaround:

Set click listeners in code. For NavigationView, use setNavigationItemSelectedListener().

UPDATE: This bug has ben fixed

You can now use XML onClick in Support Library 23.1 (bug report). I've verified it works in my app. But there seems to be other (newer) XML issues with NavView in v23.1 (see below), even though this particular onClick error is now fixed.

For completeness:

There appears to be another (related?) bug when inflating NavigationView header via XML. Using XML app:headerLayout produces errors with 23.1, even though XML onClick now works. Because of this inflation issue, you'll need to use NavigationView.inflateHeaderView() method in code. This new method was added in 23.1 and, apparently, the previous XML inflate is now broken (or maybe they deprecated app:headerLayout without telling anyone?). More info detailed here.

Community
  • 1
  • 1
hungryghost
  • 9,463
  • 3
  • 23
  • 36
  • I have implemented switch case on setNavigationItemSelected..(). to open various fragments. It works well for Phone layout but Upon twopane layout , the same code doesn't work. the Default case is triggered . meaning the ids for MenuItem has changed. – Y2K Sep 14 '15 at 11:21
1

Hi: my solution is remove

app:headerLayout="@layout/drawer_header"

from your NavigationView layout as below:

<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>

And then use below in your activity or view controller

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

this works for me.

Summer
  • 27
  • 7
  • Sorry. As I said in my original post, we obviously can add the onClick in Java. The bug is that onClick was not working from XML. Anyway, this point is moot now since Google has released a bug fix. See my updated post for info. – hungryghost Oct 23 '15 at 00:19
  • I saw the bug that google fixed ,I use Support Library 23.1 , but, It can not add the onClick unless you use `navigationView.inflateHeaderView(R.layout.nav_header);` to load the view . via xml can not set onClick in NavigationView for headerView. – Summer Oct 23 '15 at 01:06
  • That appears to be another bug with inflating NavigationView header via XML. I had the same problem with v23.1, but XML `onClick` works fine now (I've verified in my app). It's just that now XML `app:headerLayout` is broken, so you're forced to use `inflateHeaderView()` in code. This method was just added in 23.1, so looks like they broke something in the implementation. One step forward, one step back. I searched for info about this XML `app:headerLayout` problem last week, but didn't find anything. Maybe you want to post a new question for it? – hungryghost Oct 23 '15 at 03:35
  • Oh, looks like other people have already posted about this inflate issue since I last looked. http://stackoverflow.com/a/33163288/3449044 – hungryghost Oct 23 '15 at 04:06
0

You may write your method in code without mentioning it in XML. In code you just use the code

public void methodName()
{
//
}

View v = findViewById(R.id.view_id);
v.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
methodName();
}
});
Vendetta8247
  • 592
  • 1
  • 5
  • 30
  • I know I can add an onClickListener, and that's what I'm already doing to get around this problem. I'm wondering why XML onClick doesn't work. I think it may be a bug with the new support library. – hungryghost May 31 '15 at 02:26
  • 1
    @hungryghost to be honest I have never gotten into it very much as long as the coding way of doing it looks prettier to me and it simply works. But I will keep an eye on this post just in case I find out something interesting – Vendetta8247 May 31 '15 at 02:29
  • Coding it works fine and is easy enough. But in my particular implementation, I'm actually going to be doing more complex swapping of layouts and such, and XML onClick would make it slightly easier. But that's really besides the point. For me, I'm just surprised by this error. I have no idea why it wouldn't work. Also, I should probably modify my question to make it more clear what I'm asking. I have a feeling I'll get lots more "just use OnClickLIstener" answers unless I'm more explicit! – hungryghost May 31 '15 at 02:33
  • 1
    @hungryghost by the way sorry that I made it an answer. It should have been a comment. I just don't have 50 reputation and in case it could help I had to answer – Vendetta8247 May 31 '15 at 04:41
  • 1
    oh no problem. That's fine you made it an answer. I'd mark it as correct, but it's not really what I was asking. I edited my original question to make it clearer what I'm talking about. Good luck getting that 50 rep. I'll upvote your comment to help. Almost there! – hungryghost May 31 '15 at 05:50
-1

NavigationView has an OnNavigationItemSelectedListener for the Menu Items.

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

}

For the Header you can do something like this e.g

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

Reference for my 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" />

Hiroga Katageri
  • 1,345
  • 3
  • 21
  • 40
  • Sorry, I think you're misunderstanding the question. I am not asking how to add a click listener in code. My question is why is there an error with xml onClick. I'm pretty sure it's a bug in the library. – hungryghost Jun 04 '15 at 09:34