Android Sliding Menu like Facebook, Youtube, Google+

    In Android SDK, there is a widget use for making a Sliding Menu called Navigation Drawer. It's quite easy to approach and using in our application.
    But if you would like to make a Sliding Menu like Facebook, you must use third-party library. Now a days most of the android application uses this sliding menu style, which must include Youtube, Facebook,  LinkedIn,...

    Today I am going to explain how to make this sliding menu type  in an android application.

1. Download and import project

    SlidingMenu is a famous project in Android. You can download it from @Github. This library required ActionBarSherlock, so you must download it from actionbarsherlock.com, too.
    After that, import 2 libraries to Android Studio project, it will become 2 modules called "library" and "actionbarsherlock".
NOTE: More details about importing Eclipse project to Android Studio module, you can see my previous post.
    After done, you will see your app/build.gradle like this:
build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.2"

    defaultConfig {
        applicationId "com.blogspot.hongthaiit.slidemenu"
        minSdkVersion 14
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile 'com.android.support:appcompat-v7:22.0.0'
    compile project(':library')
    compile project(':actionbarsherlock')
}

2. Coding project core

    Make a simple activity layout (only a FrameLayout as root):
activity_slide.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</FrameLayout>

     In activity programmatically code, we set some properties for Sliding Menu at onCreate() method (this activity must extends SlidingActivity or SlidingFragmentActivity):
SlidingActivity.java

package com.blogspot.hongthaiit.slidemenu;

import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.Fragment;
import android.view.MenuItem;

import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu;
import com.jeremyfeinstein.slidingmenu.lib.app.SlidingFragmentActivity;


public class SlidingActivity extends SlidingFragmentActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sliding);

        //set menu view for sliding menu in this activity
        setBehindView();

        // customize the SlidingMenu
        SlidingMenu sm = getSlidingMenu();
        sm.setShadowWidthRes(R.dimen.shadow_width);
        sm.setShadowDrawable(R.drawable.shadow);
        sm.setBehindOffsetRes(R.dimen.slidingmenu_offset);
        sm.setFadeDegree(0.35f);
        sm.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);

        getActionBar().setIcon(R.mipmap.menu);
        getActionBar().setHomeButtonEnabled(true);
    }

    private void setBehindView() {
        setBehindContentView(R.layout.menu_slide);

        //transaction fragment to sliding menu
        transactionFragments(MenuFragment.newInstance(), R.id.menu_slide);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                toggle();
                return true;

        }
        return super.onOptionsItemSelected(item);
    }

    /**
     * Replace fragment by fragment transaction
     * @param fragment
     * @param viewResource
     */
    public void transactionFragments(Fragment fragment, int viewResource) {
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        ft.replace(viewResource, fragment);
        ft.commit();
        toggle();
    }
}

    Now, we'll create the menu layout (called BehindView of Sliding Menu). Designing a simple layout has only a container layout (FrameLayout):
menu_slide.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/menu_slide"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</FrameLayout>

    In this menu layout, we replace a Fragment which contains a ListView (you may using ListFragment directly). Layout (xml file) for this fragment:
fragment_menu.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="none">

        </ListView>
</FrameLayout>

    Customizing a ListView  adapter with data in programmatically code like this:
MenuFragment.java

package com.blogspot.hongthaiit.slidemenu;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class MenuFragment extends Fragment {

    private View rootView;
    private ListView listView;
    private ArrayList<SlidingMenuItem> listMenuItems;
    private final static String TAG = "MenuFragment";

    public static Fragment newInstance() {
        MenuFragment fragment = new MenuFragment();
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //create menu items
        listMenuItems = new ArrayList<SlidingMenuItem>();
        listMenuItems.add(new SlidingMenuItem(R.mipmap.mercury, "Mecury"));
        listMenuItems.add(new SlidingMenuItem(R.mipmap.venus, "Venus"));
        listMenuItems.add(new SlidingMenuItem(R.mipmap.earth, "Earth"));
        listMenuItems.add(new SlidingMenuItem(R.mipmap.mars, "Mars"));
        listMenuItems.add(new SlidingMenuItem(R.mipmap.jupiter, "Jupiter"));
        listMenuItems.add(new SlidingMenuItem(R.mipmap.saturn, "Saturn"));
        listMenuItems.add(new SlidingMenuItem(R.mipmap.uranus, "Uranus"));
        listMenuItems.add(new SlidingMenuItem(R.mipmap.neptune, "Neptune"));
    }

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        rootView = inflater.inflate(R.layout.fragment_menu, container, false);
        listView = (ListView) rootView.findViewById(R.id.list);

        return rootView;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        setListViewAdapter();
    }

    private void setListViewAdapter() {
        SlidingMenuAdapter adapter = new SlidingMenuAdapter(getActivity(), R.layout.item_menu, listMenuItems);
        listView.setAdapter(adapter);
        listView.setOnItemClickListener(onItemClickListener());
        Log.i(TAG, "create adapter " + listMenuItems.size());
    }

    /**
     * Go to fragment when menu item clicked!
     *
     * @return
     */
    private AdapterView.OnItemClickListener onItemClickListener() {
        return new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                SlidingMenuItem item = (SlidingMenuItem) parent.getItemAtPosition(position);
                ((SlidingActivity) getActivity()).transactionFragments(PageFragment.newInstance(item.getMenuItemName()),
                        R.id.container);
            }
        };
    }

    /**
     * private class to make a listview adapter based on ArrayAdapter
     */
    private class SlidingMenuAdapter extends ArrayAdapter<SlidingMenuItem> {

        private FragmentActivity activity;
        private ArrayList<SlidingMenuItem> items;

        public SlidingMenuAdapter(FragmentActivity activity, int resource, ArrayList<SlidingMenuItem> objects) {
            super(activity, resource, objects);
            this.activity = activity;
            this.items = objects;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder = null;
            LayoutInflater inflater = (LayoutInflater) activity
                    .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
            // If holder not exist then locate all view from UI file.
            if (convertView == null) {
                // inflate UI from XML file
                convertView = inflater.inflate(R.layout.item_menu, parent, false);
                // get all UI view
                holder = new ViewHolder(convertView);
                // set tag for holder
                convertView.setTag(holder);
            } else {
                // if holder created, get tag from view
                holder = (ViewHolder) convertView.getTag();
            }

            holder.itemName.setText(getItem(position).getMenuItemName());
            holder.itemImage.setImageResource(getItem(position).getImageResource());

            return convertView;
        }

        private class ViewHolder {
            private TextView itemName;
            private ImageView itemImage;

            public ViewHolder(View v) {
                itemName = (TextView) v.findViewById(R.id.name);
                itemImage = (ImageView) v.findViewById(R.id.image);
            }
        }
    }
}

     As you can see in MenuFragment code, when click at each ListView row (item) in menu, app will replace a Fragment to our SlidingActivity above. Here is source code of  PageFragment:
PageFragment.java

package com.blogspot.hongthaiit.slidemenu;

import android.graphics.Typeface;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class PageFragment extends Fragment {
    private static final String TAG = "PageFragment";
    private String fragmentName;
    private View root;

    public static PageFragment newInstance(String fragmentName) {
        PageFragment fragment = new PageFragment();
        Bundle args = new Bundle();
        args.putString("fragment_name", fragmentName);
        fragment.setArguments(args);

        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            fragmentName = getArguments().getString("fragment_name");
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        root = inflater.inflate(R.layout.fragment_page, container, false);

        //locate view element and setting data
        TextView textView = (TextView)root.findViewById(R.id.fragment_name);
        textView.setText(fragmentName);

        return  root;
    }
}

    And it's layout:
fragment_page.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:background="@android:color/holo_green_dark"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/fragment_name"
        android:layout_width="match_parent"
        android:layout_centerInParent="true"
        android:gravity="center"
        android:textSize="20sp"
        android:textStyle="bold"
        android:textColor="@android:color/holo_red_dark"
        android:layout_height="wrap_content" />
</RelativeLayout>

3. Some more necessary files

- Layout for each menu row (each ListView row):
item_menu.xml
<?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="wrap_content"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/image"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="30"
        android:contentDescription="@string/app_name" />

    <TextView
        android:id="@+id/name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_weight="70"
        android:gravity="center"/>
</LinearLayout>

- Setting Sliding Menu ShadowDrawable in SlidingActivity with this layout:
shadow.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >

    <gradient
        android:endColor="#33000000"
        android:centerColor="#11000000"
        android:startColor="#ffffff" />

</shape>

4. Running application

    After running program, output will be like this video:


Share


Previous post
« Prev Post
Next post
Next Post »