2

I have developed a Material Design based Navigation Drawer containing a Header View, following this tutorial: How To Make Material Design Navigation Drawer With Header View.

I am trying to add a separator with a category name underneath it but there seem to be a problem with the position of the dataset corresponding to my separator. This means that the separator loads correctly, but not in the position where I want it to be. Basically what I I've tried to do is to pass an ArrayList of "DrawerItem" objects into "MyAdapter" class extending RecyclerView. The arraylist contains everything: -the header's parameters -the items names and icons -and the separator, devised itself also as a DrawerItem object but with only a string as title (in my case "Others").

This is my code:

DrawerItem:

package madapps.materialdesignappbar;

public class DrawerItem {

    String ItemName;
    int imgResID;
    String title;

    String name ;
    String email ;
    int profile  ;

public DrawerItem(String Name, String Email, int profileResID){
    name = Name;
    email = Email;
    profile = profileResID;
}

public DrawerItem(String itemName, int imgResID) {
    ItemName = itemName;
    this.imgResID = imgResID;
}
//separator case
public DrawerItem(String title) {
    this(null, 0);
    this.title = title;
    this.ItemName = "separator";
}

public String getTitle(){
    return title;
}
public void setTitle(String title){
    this.title = title;
}

public String getItemName() {
    return ItemName;
}

public int getImgResID() {
    return imgResID;
}

public void setItemName(String itemName) {
    this.ItemName = itemName;
}

public void setImgResID(int imgResID) {
    this.imgResID = imgResID;
}

public void setName(String Name){
    this.name = Name;
}

public void setEmail(String Email){
    this.email = Email;
}

public void setProfile(int Profile){
    this.profile = Profile;
}

public String getName(){
    return name;
}
public String getEmail(){
    return email;
}
public int getProfile(){
    return profile;
}

}

MyAdapter

package madapps.materialdesignappbar;

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

private static final int TYPE_HEADER = 0;  // Declaring Variable to Understand which View is being worked on
// IF the view under inflation and population is header or Item
private static final int TYPE_ITEM = 1;
private static final int TYPE_SEPARATOR = 2;

private ArrayList<DrawerItem> data;

MyAdapter(ArrayList<DrawerItem> Data){
    // MyAdapter Constructor with titles and icons parameter
    // titles, icons, name, email, profile pic are passed from the main activity as we have seen earlier
    data = Data;
}
// Creating a ViewHolder which extends the RecyclerView View Holder
// ViewHolder are used to to store the inflated views in order to recycle them
public static class ViewHolder extends RecyclerView.ViewHolder {
    int Holderid;

    LinearLayout itemLayout;
    TextView textView;
    ImageView imageView;
    ImageView profile;
    TextView Name;
    TextView email;
    TextView drawerTitle;
    LinearLayout separatorLayout;
    // Creating ViewHolder Constructor with View and viewType As a parameter
    public ViewHolder(View itemView, int ViewType) {
        super(itemView);
        // Here we set the appropriate view in accordance with the
        // the view type as passed when the holder object is created
        if (ViewType == TYPE_HEADER){
            Name = (TextView) itemView.findViewById(R.id.name);           // Creating Text View object from header.xml for name
            email = (TextView) itemView.findViewById(R.id.email);         // Creating Text View object from header.xml for email
            profile = (ImageView) itemView.findViewById(R.id.circleView); // Creating Image view object from header.xml for profile pic

            Holderid = 0; // Setting holder id = 0 as the object being populated are of type header view
        }
        if(ViewType == TYPE_ITEM) {

            textView = (TextView) itemView.findViewById(R.id.rowText);   // Creating TextView object with the id of textView from item_row.xml
            imageView = (ImageView) itemView.findViewById(R.id.rowIcon); // Creating ImageView object with the id of ImageView from item_row.xml

            Holderid = 1;                                                 // setting holder id as 1 as the object being populated are of type item row
        }
        if(ViewType == TYPE_SEPARATOR){
            drawerTitle = (TextView) itemView.findViewById(R.id.drawerTitle);

            Holderid = 2;
        }
    }
}

//Below first we Override the method onCreateViewHolder which is called when the ViewHolder is
//Created, In this method we inflate the item_row.xml layout if the viewType is Type_ITEM or else we inflate header.xml
// if the viewType is TYPE_HEADER
// and pass it to the view holder
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    if (viewType == TYPE_HEADER) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.header, parent, false); //Inflating the layout
        ViewHolder vhHeader = new ViewHolder(v,viewType); //Creating ViewHolder and passing the object of type view

        return vhHeader; //returning the object created
    }else

    if (viewType == TYPE_ITEM) {
            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_row, parent, false); //Inflating the layout
            ViewHolder vhItem = new ViewHolder(v, viewType); //Creating ViewHolder and passing the object of type view
            return vhItem; // Returning the created object
            //inflate your layout and pass it to view holder
    }
    if (viewType == TYPE_SEPARATOR){
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.separator, parent, false);
        ViewHolder vhSeparator = new ViewHolder(v, viewType);

        return vhSeparator;
    }

    return null;
}
/* Next we override a method which is called when the item in a row is needed to be displayed,
@param position   tells us item at which position is being constructed to be displayed
@param holder     id of the holder object tell us which view type is being created 1 for item row */
@Override
public void onBindViewHolder(MyAdapter.ViewHolder holder, int position) {

    if(holder.Holderid==0) {
        holder.profile.setImageResource(data.get(0).getProfile());   // Similarly we set the resources for header view
        holder.Name.setText(data.get(0).getName());
        holder.email.setText(data.get(0).getEmail());
    }
    if(holder.Holderid == 1) {
            // as the list view is 1going to be called after the header view so we decrement the

        holder.textView.setText(data.get(position).title);
        holder.imageView.setImageResource(data.get(position).imgResID);

    }if (holder.Holderid==2){
        holder.drawerTitle.setText(data.get(4).getItemName());
    }
}

// This method returns the number of items present in the list
@Override
public int getItemCount() {
    return data.size(); 
}
// With the following method we check what type of view is being passed
@Override
public int getItemViewType(int position) {
    if (isPositionHeader(position)) {//if position == 0 return true
        return TYPE_HEADER;     //0
    }
    if(isSeparator(position)){
        return TYPE_SEPARATOR;
    }
        return TYPE_ITEM;
}
private boolean isSeparator(int position){
    return position==2;
}
private boolean isPositionHeader(int position) {
    return position == 0;
}

}

As you can see I am populating the ArrayList of DrawerItem with three kinds of objects, in this order (code from MainActivity):

ArrayList data = new ArrayList<DrawerItem>();

    data.add(new DrawerItem("Chris Benois","chris_benois@mail.com",R.mipmap.aka));

    data.add( new DrawerItem("Home",R.mipmap.ic_home));
    data.add( new DrawerItem("Events",R.mipmap.ic_events));
    data.add( new DrawerItem("Mail", R.mipmap.ic_mail));
    data.add(new DrawerItem("Others"));
    data.add( new DrawerItem("Shop", R.mipmap.ic_shop));
    data.add( new DrawerItem("Travel", R.mipmap.ic_travel));

the problem is that my "separator" separator doesn't come up where I want it to be (just before "Shop" item), but elsewhere as shown in this image:

Navigation Drawer

How can I move it where I want to?

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Cris
  • 2,002
  • 4
  • 30
  • 51

1 Answers1

3

Don't know if you have found a solution yet, but as your question helped me with recycler view, I thought I would see if I can return the favour.

I've found the most important method in the ViewHolder class is getItemViewType(int position). In the code you've posted you seem to be returning 2 for your TYPE_SEPARATOR without properly checking the position of the elements in the navigation drawer, which is why your divider is appearing below home in the navigation drawer. You need to be checking for the 5th position and then returning your TYPE_SEPARATOR.

I used separators in my drawer by creating a new layout when it hit my 6th element by passing the ViewHolder a different type:

 public int getItemViewType(int position) {
    if (position == 0) {
        return TYPE_HEADER;
    } else if (position>0 && position <6) {
        return TYPE_TAG;
    } else if (position ==6) {
        return TYPE_DIVIDER;
    }
    else
        return TYPE_ICON;


}

and in my ViewHolder constructor:

public ViewHolder(View itemView, int viewType) {
        super(itemView);


        if(viewType == TYPE_HEADER)
        {

            name = (TextView) itemView.findViewById(R.id.name);
            email = (TextView) itemView.findViewById(R.id.email);
            profile = (ImageView) itemView.findViewById(R.id.image_view);
            holderId = 0;

        }

        if (viewType == TYPE_TAG)
        {

            tagText = (TextView) itemView.findViewById(R.id.tag);
            holderId = 1;


        }

        if(viewType == TYPE_ICON)
        {
            iconText = (TextView) itemView.findViewById(R.id.rowText);
            icon = (ImageView) itemView.findViewById(R.id.rowIcon);
            holderId = 2;


        }

        if(viewType == TYPE_DIVIDER)
        {
            dividerText = (TextView) itemView.findViewById(R.id.rowText);
            dividerIcon = (ImageView) itemView.findViewById(R.id.rowIcon);


            holderId = 3; 
        }


    }

}

and in my onCreateViewHolder method I just inflated a different layout for TYPE_DIVIDER.

Hope it helps.

EDIT

I have since created a working recycler view, and I do not recommend inflating a different layout for your divider. It caused me all sorts of problems. You should use RecyclerView.ItemDecoration. Here are some great posts on SO, How to add dividers and spaces between items in RecyclerView?.

Community
  • 1
  • 1
JupiterT
  • 338
  • 3
  • 10
  • can i see your `TYPE_DIVIDER`layout? or we need to just add a divider code only? – ʍѳђઽ૯ท Jun 30 '15 at 06:24
  • Sorry, AndroidDev, I dropped recycler view in the end so I no longer have the layout. I can't exactly remember why. I think it was just taking up too much of my time to implement properly. – JupiterT Jul 07 '15 at 21:24