Update: With the release of Design Support Library 23.1.1, the following method has been added to address this issue:
/**
* Gets the header view at the specified position.
*
* @param index The position at which to get the view from.
* @return The header view the specified position or null if the position does not exist in this
* NavigationView.
*/
public View getHeaderView(int index) {
...
}
You can also retrieve the number of headers, in case you have more than one:
/**
* Gets the number of headers in this NavigationView.
*
* @return A positive integer representing the number of headers.
*/
public int getHeaderCount() {
...
}
In other words, if you use the headerLayout
attribute, you can now get access to the view using above method:
View header = navigationView.getHeaderView(0);
ImageView navProfile = (ImageView) header.findViewById(R.id.navProfilePic);
Original answer below left intact for background and/or educational purposes.
I'm going to make an educated guess and say that the following line is probably inflating a view from your NavigationView
's header layout:
final ImageView navProfile = (ImageView) findViewById(R.id.navProfilePic);
Where the header layout is given to the NavigationView
using:
app:headerLayout="@layout/nav_drawer_header"
If so, continue reading...
With the 23.1.0 release of the design support library, the internal implementation of NavigationView
changed to leverage RecyclerView
(rather than ListView
). With that change, the header has now become another 'item' in the view, meaning it doesn't become available until after the initial layout pass. As such, with your current code, when the findViewById()
lookup executes, the RecyclerView
hasn't set up the header yet, and hence the result of the lookup ends up being null
.
The 'issue' has been reported and the consensus is that getting the header view is going to be exposed with a new method on the NavigationView
(most likely just called getHeaderView()
). Until this is rolled out, there are two obvious workarounds I'm aware of.
Workaround #1:
Remove app:headerLayout
and inflate and add the header view manually. Then use the resulting layout to look up any views in the header.
View header = navigationView.inflateHeaderView(R.layout.nav_drawer_header);
ImageView navProfile = (ImageView) header.findViewById(R.id.navProfilePic);
Workaround #2:
Don't inflate views until after the initial layout pass. This can easily be accomplished by posting a Runnable
to the view's parent's internal message queue, so it gets executed after any pending messages.
View parent = (View) mNavigationView.getParent();
parent.post(new Runnable() {
@Override public void run() {
ImageView navProfile = (ImageView) mNavigationView.findViewById(R.id.navProfilePic);
}
});
Personally, I'd go with #1.
Related: