184

In my NavigationView I have a header layout with id 'viewId' with active buttons. To setup those buttons, I do the following in activity's onPostCreate:

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

With new version android support library, (23.1.0), the view can't be found, it returns null. With previous versions it worked well. Is it a bug or am I using this feature wrong? If so, how to access header layout and add behavior to it?

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
khusrav
  • 5,267
  • 5
  • 27
  • 38

10 Answers10

455

Version 23.1.0 switches NavigationView to using a RecyclerView (rather than the previous ListView) and the header is added as one of those elements. This means it is not instantly available to call findViewById() - a layout pass is needed before it is attached to the NavigationView.

For version 23.1.1 of the Support Library, you can now get a reference to the header view using getHeaderView():

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

This has the advantage of working on headers added via XML and via code.

If you are still using 23.1.0, as per the related bug, you can inflate the header in code and use findViewById() on that:

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

Until you move to 23.1.1.

ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
  • `OnLayoutChangeListener` requires min sdk level 11, but I have 9 in my app. Any ideas please, how to workaround `findViewById` returning `null` for `NavigationView` header? – Alexander Farber Oct 18 '15 at 20:40
  • 3
    @AlexanderFarber - the code I posted works back to API 7 – ianhanniballake Oct 18 '15 at 21:10
  • 4
    I prefer to downgrade libs. Introducing a bug is like a signature from Google. If the new version has a bug, then Google released that new version – BamsBamx Oct 19 '15 at 21:13
  • @GFPF - the accepted answer is strictly worse (`inflate(R.layout.lay_header, null);` will cause all `layout_` attributes to be ignored, while this solution does not) and accomplishes the same result. – ianhanniballake Oct 27 '15 at 03:01
  • @ianhanniballake This is true, but the method [inflateHeaderView](http://developer.android.com/intl/pt-br/reference/android/support/design/widget/NavigationView.html#inflateHeaderView(int)) has not any overloading that consider set header view with "attachToRoot" true in method [inflate](http://developer.android.com/intl/pt-br/reference/android/view/LayoutInflater.html#inflate(int, android.view.ViewGroup, boolean)). How to solve it in the best way without ignoring the attributes? – GFPF Nov 03 '15 at 03:08
  • 1
    @GFPF - when you call `inflateHeaderView`, it attaches the View for you in the correct layer in the `RecyclerView` with the correct parent - something that you cannot do externally to `NavigationView`. – ianhanniballake Nov 03 '15 at 04:08
  • This method comes with the issue that if the header is already defined inside the xml file, calling inflateheader adds an extra header in the side drawer. – RmK Nov 17 '15 at 08:56
  • 1
    @RmK - thanks, I've updated to answer to reflect the new APIs added in 23.1.1 to retrieve headers added via XML (as the previous workaround only worked on headers added via code). – ianhanniballake Nov 17 '15 at 17:56
  • I really like how Google changes major part of view control in each and every sdk update, not. – Adam Varhegyi Mar 07 '16 at 10:23
  • `getHeaderView(0)`.. i thought that the 0 the the index of the View but it's obvious that it is not, thanks. – Mousa Alfhaily May 19 '17 at 21:25
152

Now with the 23.1.1 release of the design support library, you can use

NavigationView navigationView = (NavigationView) findViewById(R.id.your_nav_view_id);
View header = navigationView.getHeaderView(0)
TextView text = (TextView) header.findViewById(R.id.textView);
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Francois Dermu
  • 4,437
  • 2
  • 22
  • 14
14

This is how I did it using ButterKnife and it works for me.

protected static class HeaderViewHolder {

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

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

and then use this view holder like this :

View header = navigationView.getHeaderView(0);
headerViewHolder = new HeaderViewHolder(header);
Wahib Ul Haq
  • 4,185
  • 3
  • 44
  • 41
9

For me that was the same situation with 23.1.0, after of update the null pointer exception become. In this case the NavigatorView look like:

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

I tried the solution proposal by ianhanniballake but it does not work. Then I inflated with the sentence:

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

After that, I can find by id all views defined in nav_heardlayout .

Javier C.
  • 7,859
  • 5
  • 41
  • 53
Campino
  • 682
  • 7
  • 11
5
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 ")
Jin Lee
  • 3,194
  • 12
  • 46
  • 86
indrit saveta
  • 127
  • 1
  • 6
4
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 ");
indrit saveta
  • 127
  • 1
  • 6
  • Hello and welcome to Stack Overflow! Please add some text explaining how this solves the question asked above. Thanks! – Jonathan Mar 19 '19 at 17:23
1

In Kotlin @Francois Dermu code be like

val navigationView : NavigationView = findViewById(R.id.your_nav_view_id);
val header = navigationView.getHeaderView(0)
val textView = header.findViewById<TextView>(R.id.textView)
Alex
  • 8,908
  • 28
  • 103
  • 157
1

Kotlin version.

val navView: NavigationView = findViewById(R.id.nav_view)       
// set User Name
val headerView: View = navView.getHeaderView(0)
headerView.txtUserName.text = "User Name Goes here"
Qadir Hussain
  • 8,721
  • 13
  • 89
  • 124
1

Works for me in java

   navigationView = findViewById(R.id.nav_view);
    View viewHeader = navigationView.getHeaderView(0);
    ((TextView)viewHeader.findViewById(R.id.tv_name)).setText(preferences.getString(MyConstant.NAME,"n/a"));
harry
  • 171
  • 1
  • 4
0

Here is how to change a username in a drawer.

NavigationView mNavigationView = findViewById(R.id.nav_view);
View mHeaderView = mNavigationView.getHeaderView(0);
TextView usernameTextview = mHeaderView.findViewById(R.id.drawer_email_textField);
Bundle b = getIntent().getExtras();
String username = b.getString("email");
usernameTextview.setText(username);

that's works for me

Benjamin Buch
  • 4,752
  • 7
  • 28
  • 51