Android : Sliding Menu – Part 2/2

This is the second part of the SlidingMenu tutorial. In this part, we will see how to create a nice menu with sections and items. For that, we will use an ExpandableListView.


Test before
If you wish to test before, you can install the application with the following link. The whole source code of the project is also available on github.

logo-app
Your app idea
Michenux
Free   
pulsante-google-play-store
pulsante-appbrain
qrcode-app

TUTORIAL PART 2/2

Describe the menu

First, we need two classes to describe the menu : Section and SectionItem.
The section has a title and a list of items.

public class Section {

    private String title;
    private List<SectionItem> sectionItems = new ArrayList<SectionItem>();

    public Section(String title) {
        this.title = title;
    }

    public void addSectionItem(long id, String title, String icon) {
        this.sectionItems.add( new SectionItem(id, title, icon));
    }
   
    public String getTitle() {
        return title;
    }
   
    public void setTitle(String title) {
        this.title = title;
    }
   
    public List<SectionItem> getSectionItems() {
        return sectionItems;
    }
   
    public void setSectionItems(List<SectionItem> sectionItems) {
        this.sectionItems = sectionItems;
    }
}

The section item has an id, a title and an icon

public class SectionItem {

    private long id;
    private String title;
    private String icon;

    public SectionItem(long id, String title, String icon) {
        this.id = id;
        this.title = title;
        this.icon = icon;
    }

    public String getTitle() {
        return title;
    }

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

    public String getIcon() {
        return icon;
    }

    public void setIcon(String icon) {
        this.icon = icon;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }
}

Layout of the sliding menu

Compared to first part of the tutorial, we need to change the layout of the sliding menu into a fragment. Edit the file res/layout/slidingmenu.xml with this content :

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
   android:name="org.michenux.yourappidea.slidingmenu.SlidingMenuFragment"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:id="@+id/slidingmenu">
</fragment>

Layout of the fragment of the sliding menu

To create the menu, we use the ExpandableListView component of the android API.
Create the file res/layout/slidingmenu_fragment.xml with the following content.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:orientation="vertical"
   android:background="@color/purple_dark" >

     <ExpandableListView android:id="@+id/slidingmenu_view"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:transcriptMode="alwaysScroll"/>
   
</LinearLayout>

Layouts for the ExpandableListView

An ExpandableListView needs two layouts : one for group (section) and one for children (section item).

Create the layout for section (res/layout/slidingmenu_sectionview.xml):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:orientation="vertical"
   android:background="@color/purple_dark">
   
    <TextView
       android:id="@+id/slidingmenu_section_title"
       style="?android:attr/listSeparatorTextViewStyle"
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:text="Section"
       android:textSize="18sp"
       android:paddingTop="7dp"
       android:paddingBottom="7dp"
       android:background="@color/purple_dark"
       android:textColor="#FFFFFF"/>
   
</LinearLayout>

And create the layout for section item (res/layout/slidingmenu_sectionitem.xml):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:background="@drawable/slidingmenu_list_selector_background">

    <ImageView
       android:id="@+id/slidingmenu_sectionitem_icon"
       android:layout_width="wrap_content"
       android:layout_height="30dp"
        android:layout_centerVertical="true"
        android:paddingLeft="15dp"/>

    <TextView
       android:id="@+id/slidingmenu_sectionitem_label"
       android:layout_width="match_parent"
       android:layout_height="50dp"
       android:layout_toRightOf="@id/slidingmenu_sectionitem_icon"
       android:gravity="center_vertical"
       android:text="TextView"
       android:textColor="#FFFFFF"/>

</RelativeLayout>

Here’s the drawable to define the color when section item is pressed (res/drawable/slidingmenu_list_selector_background.xml) :

<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_pressed="true"
        android:drawable="@color/purple_light" />
   
    <item android:state_pressed="false"
        android:drawable="@android:color/transparent" />
</selector>

Adapter for the ExpandableListView

public class SectionListAdapter extends BaseExpandableListAdapter {

    private Context context;
    private LayoutInflater inflater;
    private List<Section> sections;

    public SectionListAdapter(Context context, List<Section> sections) {
        this.sections = sections;
        this.inflater = LayoutInflater.from(context);
        this.context = context;
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return sections.get(groupPosition).getSectionItems().get(childPosition);
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return sections.get(groupPosition).getSectionItems().get(childPosition).getId();
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        return sections.get(groupPosition).getSectionItems().size();
    }

    @Override
    public Object getGroup(int groupPosition) {
        return this.sections.get(groupPosition);
    }

    @Override
    public int getGroupCount() {
        return this.sections.size();
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded,
            View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = inflater.inflate(R.layout.slidingmenu_sectionview,
                    parent, false);
        }

        TextView textView = (TextView) convertView
                .findViewById(R.id.slidingmenu_section_title);
        textView.setText(((Section) getGroup(groupPosition)).getTitle());

        return convertView;
    }

    @Override
    public View getChildView(int groupPosition, int childPosition,
            boolean isLastChild, View convertView, ViewGroup parent) {

        if (convertView == null) {
            convertView = inflater.inflate(R.layout.slidingmenu_sectionitem,
                    parent, false);
        }

        SectionItem oSectionItem = this.sections.get(groupPosition).getSectionItems().get(childPosition);
       
        TextView textView = (TextView) convertView
                .findViewById(R.id.slidingmenu_sectionitem_label);
        textView.setText(oSectionItem.getTitle());

        final ImageView itemIcon = (ImageView) convertView
                .findViewById(R.id.slidingmenu_sectionitem_icon);
        itemIcon.setImageDrawable(getDrawableByName(
                oSectionItem.getIcon(), this.context));

        return convertView;
    }
   
    public static Drawable getDrawableByName( String name, Context context ) {
        int drawableResource = context.getResources().getIdentifier(
                        name,
                        "drawable",
                        context.getPackageName());
        if ( drawableResource == 0 ) {
            throw new RuntimeException("Can't find drawable with name: " + name );
        }
        return context.getResources().getDrawable(drawableResource);
    }
}

SlidingMenuFragment

onCreateView method :

createMenu method :

onClick method :

public class SlidingMenuFragment extends Fragment implements ExpandableListView.OnChildClickListener {
   
    private ExpandableListView sectionListView;
   
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
       
        List<Section> sectionList = createMenu();
               
        View view = inflater.inflate(R.layout.slidingmenu_fragment, container, false);
        this.sectionListView = (ExpandableListView) view.findViewById(R.id.slidingmenu_view);
        this.sectionListView.setGroupIndicator(null);
       
        SectionListAdapter sectionListAdapter = new SectionListAdapter(this.getActivity(), sectionList);
        this.sectionListView.setAdapter(sectionListAdapter);
       
        this.sectionListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
              @Override
              public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
                return true;
              }
            });
       
        this.sectionListView.setOnChildClickListener(this);
       
        int count = sectionListAdapter.getGroupCount();
        for (int position = 0; position < count; position++) {
            this.sectionListView.expandGroup(position);
        }
       
        return view;
    }

    private List<Section> createMenu() {
        List<Section> sectionList = new ArrayList<Section>();

        Section oDemoSection = new Section("Demos");
        oDemoSection.addSectionItem(101,"List/Detail (Fragment)", "slidingmenu_friends");
        oDemoSection.addSectionItem(102, "Airport (AsyncTask)", "slidingmenu_airport");
       
        Section oGeneralSection = new Section("General");
        oGeneralSection.addSectionItem(201, "Settings", "slidingmenu_settings");
        oGeneralSection.addSectionItem(202, "Rate this app", "slidingmenu_rating");
        oGeneralSection.addSectionItem(203, "Eula", "slidingmenu_eula");
        oGeneralSection.addSectionItem(204, "Quit", "slidingmenu_quit");
       
        sectionList.add(oDemoSection);
        sectionList.add(oGeneralSection);
        return sectionList;
    }

    @Override
    public boolean onChildClick(ExpandableListView parent, View v,
            int groupPosition, int childPosition, long id) {

        switch ((int)id) {
        case 101:
            //TODO
            break;
        case 102:
            //TODO
            break;
        case 201:
            //TODO
            break;
        case 202:
            //TODO
            break;
        case 203:
            //TODO
            break;
        case 204:
            //TODO
            break;
        }
       
        return false;
    }
}

Icons of section items

I don’t provide them in this tutorial : create your owns.

Finally

I hope you find this tutorial useful. Don’t hesitate to communicate your customizations/optimizations so i can improve this tutorial.

Share Button

Comments

12 Responses to “Android : Sliding Menu – Part 2/2”

  1. mickael on June 19th, 2013 11:39 am

    Hello,

    I don’t see how to make relation between the main activity and “SlidingMenuFragment”
    Can you help me ?

  2. mickael on June 19th, 2013 11:50 am

    Sorry, bad question. As I’ve changed some names from yours, my project didn’t compile but now it’s good.
    Very great tuto !

  3. ray on July 5th, 2013 12:05 am

    how can you use two fragments? one for the right and one for the left?

  4. Flo on July 23rd, 2013 3:59 pm

    I cant find your code on GIT ;)
    Could you explain Adapter for the ExpandableListView
    a little bit more ? i stuck there ;)

  5. Android SlidingUpPanelLayout and slidinguppanel | BlogoSfera on September 11th, 2013 2:02 pm

    […] am having problem to incorporate the sliding menu and sliding up panel from http://www.michenux.net/android-sliding-menu-part-22-690.html Android: Up/down animated sliding menu (https://github.com/umano/AndroidSlidingUpPanel) When it […]

  6. Saiwan on September 14th, 2013 4:07 am

    Great tutorial!!!! Thx for sharing, all works fine on my project. But still stuck how can I put this slide menu to the whole activities?? So my app will look like facebook app. Need it so bad :(

  7. Michenux on September 14th, 2013 4:13 pm

    Hi,
    You have to add the SlidingMenu on all activities. You can do an abstract activity that setup the SlidingMenu and make inherit your activities from it.
    I choosed another strategy for YourAppIdea: only one activity and all screens are fragments.

  8. RO on September 21st, 2013 12:20 pm

    Thanks for great tutorial.

  9. Phana on October 13th, 2013 7:46 pm

    Nice …

  10. Peter on January 14th, 2014 2:03 pm

    How to connect this SlidingMenuFragment with Activity with menu and sherlock Action Bar? What type is slidingmenu.xml ?

  11. Peter on January 14th, 2014 2:06 pm

    My app works but does not show the contents menu, it doesn`t use SlidingMenuFragment class

  12. Hassan El Khoury on January 15th, 2014 8:32 pm

    Thank You for this great and detailed tutorial!

Leave a Reply