Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trial
Kevin Haube
12,265 PointsRecyclerView Navigation Drawer -- swap Fragments?
I'm new to RecyclerViews (as most devs are) and my understanding is that to handle onClick events for a case such as a nav drawer, you need to handle it in the Adapter class, as well as the Activity your're swapping fragments in. So here's my code:
DrawerAdapter
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
int holderId;
TextView rowText;
ImageView rowIcon;
ImageView profileImage;
TextView nameLabel;
TextView emailLabel;
private int mClickedItem;
private Fragment mFragment;
private static Fragment fragment;
public ViewHolder(View itemView, int viewType) {
super(itemView);
if(viewType == TYPE_ITEM) {
rowText = (TextView) itemView.findViewById(R.id.rowText);
rowIcon = (ImageView) itemView.findViewById(R.id.rowIcon);
holderId = 1;
} else if (viewType == TYPE_HEADER) {
nameLabel = (TextView) itemView.findViewById(R.id.name);
emailLabel = (TextView) itemView.findViewById(R.id.email);
profileImage = (ImageView) itemView.findViewById(R.id.circleView);
holderId = 0;
}
}
@Override
public void onClick(View v) {
int position = getAdapterPosition();
Fragment fragment = new CrumbsFragment();
switch (position) {
case 0:
fragment = new CrumbsFragment();
Log.d("KMH", "Working case 0");
break;
case 1:
fragment = new CrumbsFragment();
Log.d("KMH", "Working case 1");
break;
case 2:
fragment = new CrumbsFragment();
Log.d("KMH", "Working case 2");
break;
}
setFragment(fragment);
}
public void setFragment(Fragment fragment) {
mFragment = fragment;
}
public static Fragment getFragment() {
return fragment;
}
}
So, in this calss, I'm handling the event by getting the position, applying it to the switch to get the correct fragment, and then setting the fragment member variable for public access with the getters and setters.
MainActivity
mDrawerRecyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(),e.getY());
if(child!=null && mGestureDetector.onTouchEvent(e)){
Fragment fragment = DrawerAdapter.ViewHolder.getFragment();
// Insert the fragment by replacing any existing fragment
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, fragment)
.commit();
// Highlight the selected item, update the title, and close the drawer
// setTitle(TITLES[position]);
mDrawerLayout.closeDrawers();
return true;
}
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
});
This is how I'm handling the MainActivity portion. I use the getter method to get the fragment and then attempt to set it using the usual process.
Here's where the error lies: I'm getting null when I use the getter in MainActivity to get the Fragment. Now, when analyzed, I assume it's because onClick (from DrawerAdapter.ViewHolder) is not called first, or at all.
Let's troubleshoot!
1 Answer
Kevin Haube
12,265 PointsSolution:
mDrawerRecyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(),e.getY());
if(child!=null && mGestureDetector.onTouchEvent(e)){
int position = mDrawerRecyclerView.getChildAdapterPosition(child);
Fragment fragment = null;
switch (position) {
case 0:
fragment = new CrumbsFragment();
Log.d("KMH", "Working case 0");
break;
case 1:
fragment = new CrumbsFragment();
Log.d("KMH", "Working case 1");
break;
case 2:
fragment = new CrumbsFragment();
Log.d("KMH", "Working case 2");
break;
default:
fragment = new CrumbsFragment();
Log.d("KMH", "Working default case");
break;
}
// Insert the fragment by replacing any existing fragment
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, fragment)
.commit();
// Highlight the selected item, update the title, and close the drawer
setTitle(TITLES[position]);
mDrawerLayout.closeDrawers();
return true;
}
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
});
The solution is to get the child view of the RecyclerView, then use it as a param and call .getChildAdapterPosition(child); on your RecyclerView. :)