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

Leave a Reply