Total Pageviews

Thursday 18 September 2014

Android Activity Life Cycle between two Activities

Hello, I want to share my experience when I faced some problems/obstructions while working related to android life cycle. Please guide me in correct way if I am wrong anywhere. 

Q1) Explain the flow of activity life cycle when control transfers from Activity 'A' to Activity 'B'.

Ans) Accoding to my observation, when control transfers from A to B, following methods will executed.

        

Explanation: 
                                   1) onPause( ) method of Activity A will be called.
                                   2) onCreate() method of Activity B will be called.
                                   3) onResume() method of Activity B will be called.
                                   4) onStop() method of activity A will be called.


Q2) Explain the flow of activity life cycle when user presses back button in Activity 'B'.

Ans) When user presses back button in Activity B, then Activity A will get focussed. The following methods will be executed.


Explanation: 
                                   1) onPause( ) method of Activity B will be called.
                                   2) onRestart() method of Activity A will be called.
                                   3) onResume() method of Activity A will be called.
                                   4) onStop() method of activity B will be called.
                                   5) onDestroy() method of activity B will be called.




Wednesday 16 July 2014

Android - Sliding Menu With Expandable List

Hi, I will share my experience while working with sliding menu without using Navigation Drawer and Action Bar.
Objective : Develop Android project with sliding menu with motion events and menu with expandable listview.
Expandable ListView : I created 5 parent groups and 3 children's for every even parent group. Instead of normal Strings, I tried to use Data Transfer Objects.
When parent group clicked, then child groups need to open if present.
When child group clicked , then parent group selection color needs to change.
Above are the requirements I have taken while developing this project.

Thanks to Paul Grime, for giving this Scrolling Menu.

Project Structure : 

Step 1: After creating android project, create new android xml file and named it as activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<com.slidingview.MyHorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_margin="0px"
    android:background="#00ffffff"
    android:fadingEdge="none"
    android:fadingEdgeLength="0px"
    android:padding="0px"
    android:scrollbars="none" >

    <LinearLayout
        android:id="@+id/top"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_margin="0px"
        android:orientation="horizontal"
        android:padding="0px" >
    </LinearLayout>

</com.slidingview.MyHorizontalScrollView>

Step 2 : we need to create two more layout files, one for menu drawer and another for main application. Then create new android xml file and named it as main_application.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/app"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#222222" >

    <RelativeLayout
        android:id="@+id/listImages_content"
        android:layout_width="match_parent"
        android:layout_height="fill_parent"
        android:background="@color/black" >

        <RelativeLayout
            android:id="@+id/home_tabBar"
            android:layout_width="match_parent"
            android:layout_height="30dp"
            android:layout_marginBottom="1dp"
            android:background="@color/thickgray"
            android:orientation="horizontal" >

            <ImageView
                android:id="@+id/slideBtn"
                android:layout_width="25dp"
                android:layout_height="25dp"
                android:layout_marginLeft="10dp"
                android:padding="3dp"
                android:src="@drawable/slide" />
        </RelativeLayout>

        <RelativeLayout
            android:id="@+id/total_frame_content"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_below="@id/home_tabBar" >

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:layout_centerVertical="true"
                android:text="Sliding Menu Demo"
                android:textColor="@android:color/white" />
        </RelativeLayout>
    </RelativeLayout>


</RelativeLayout>

and it will look like below :

I have kept a sliding button on top left of the layout to toggle the menu and create new android layout file and named it as menu_drawer.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/menu1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/thickgray"
    android:orientation="horizontal" >

    <LinearLayout
        android:id="@+id/menu"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="@color/thickgray"
        android:orientation="vertical" >

        <RelativeLayout
            android:id="@+id/category_relView"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="@color/thickgray"
            android:visibility="visible" >

            <ExpandableListView
                android:id="@+id/categorylist"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_alignParentTop="true"
                android:background="@color/thickgray"
                android:dividerHeight="0dp"
                android:groupIndicator="@null"
                android:listSelector="@android:color/transparent" />
        </RelativeLayout>
    </LinearLayout>

    <RelativeLayout
        android:id="@+id/drawerCloseLayout"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:layout_alignRight="@+id/menu"
        android:background="@drawable/shadow" >

        <ImageButton
            android:id="@+id/left_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:background="@android:color/transparent"
            android:onClick="closeDrawerFunction"
            android:src="@drawable/closedrawer"
            android:visibility="visible" />
    </RelativeLayout>

</RelativeLayout>

and it will look like below :
 I have kept item selected with sky blue color.

Step 3 : Create java class and named it as MyHorizontalScrollView.java, this class is responsible for sliding menu.

/*
 * #%L
 * SlidingMenuDemo
 * $Id:$
 * $HeadURL:$
 * %%
 * Copyright (C) 2012 Paul Grime
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
package com.slidingview;

import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.HorizontalScrollView;

/**
 * A HorizontalScrollView (HSV) implementation that disallows touch events (so no scrolling can be done by the user).
 *
 * This HSV MUST contain a single ViewGroup as its only child, and this ViewGroup will be used to display the children Views
 * passed in to the initViews() method.
 */
public class MyHorizontalScrollView extends HorizontalScrollView {
public MyHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}

public MyHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}

public MyHorizontalScrollView(Context context) {
super(context);
init(context);
}

void init(Context context) {
// remove the fading as the HSV looks better without it
setHorizontalFadingEdgeEnabled(false);
setVerticalFadingEdgeEnabled(false);
}

/**
* @param children
*            The child Views to add to parent.
* @param scrollToViewIdx
*            The index of the View to scroll to after initialisation.
* @param sizeCallback
*            A SizeCallback to interact with the HSV.
*/
public void initViews(View[] children, int scrollToViewIdx, SizeCallback sizeCallback) {
// A ViewGroup MUST be the only child of the HSV
ViewGroup parent = (ViewGroup) getChildAt(0);

// Add all the children, but add them invisible so that the layouts are calculated, but you can't see the Views
for (int i = 0; i < children.length; i++) {
children[i].setVisibility(View.INVISIBLE);
parent.addView(children[i]);
}

// Add a layout listener to this HSV
// This listener is responsible for arranging the child views.
OnGlobalLayoutListener listener = new MyOnGlobalLayoutListener(parent, children, scrollToViewIdx, sizeCallback);
getViewTreeObserver().addOnGlobalLayoutListener(listener);
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
// Do not allow touch events.
return false;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// Do not allow touch events.
return false;
}

/**
* An OnGlobalLayoutListener impl that passes on the call to onGlobalLayout to a SizeCallback, before removing all the Views
* in the HSV and adding them again with calculated widths and heights.
*/
class MyOnGlobalLayoutListener implements OnGlobalLayoutListener {
ViewGroup parent;
View[] children;
int scrollToViewIdx;
int scrollToViewPos = 0;
SizeCallback sizeCallback;

/**
* @param parent
*            The parent to which the child Views should be added.
* @param children
*            The child Views to add to parent.
* @param scrollToViewIdx
*            The index of the View to scroll to after initialisation.
* @param sizeCallback
*            A SizeCallback to interact with the HSV.
*/
public MyOnGlobalLayoutListener(ViewGroup parent, View[] children, int scrollToViewIdx, SizeCallback sizeCallback) {
this.parent = parent;
this.children = children;
this.scrollToViewIdx = scrollToViewIdx;
this.sizeCallback = sizeCallback;
}

@Override
public void onGlobalLayout() {
// System.out.println("onGlobalLayout");

final HorizontalScrollView me = MyHorizontalScrollView.this;

// The listener will remove itself as a layout listener to the HSV
me.getViewTreeObserver().removeGlobalOnLayoutListener(this);

// Allow the SizeCallback to 'see' the Views before we remove them and re-add them.
// This lets the SizeCallback prepare View sizes, ahead of calls to SizeCallback.getViewSize().
sizeCallback.onGlobalLayout();

parent.removeViewsInLayout(0, children.length);

final int w = me.getMeasuredWidth();
final int h = me.getMeasuredHeight();

// System.out.println("w=" + w + ", h=" + h);

// Add each view in turn, and apply the width and height returned by the SizeCallback.
int[] dims = new int[2];
scrollToViewPos = 0;
for (int i = 0; i < children.length; i++) {
sizeCallback.getViewSize(i, w, h, dims);
// System.out.println("addView w=" + dims[0] + ", h=" + dims[1]);
children[i].setVisibility(View.VISIBLE);
parent.addView(children[i], dims[0], dims[1]);
if (i < scrollToViewIdx) {
scrollToViewPos += dims[0];
}
}

// For some reason we need to post this action, rather than call immediately.
// If we try immediately, it will not scroll.
new Handler().post(new Runnable() {
@Override
public void run() {
me.scrollBy(scrollToViewPos, 0);
}
});
}
}

/**
* Callback interface to interact with the HSV.
*/
public interface SizeCallback {
/**
* Used to allow clients to measure Views before re-adding them.
*/
public void onGlobalLayout();

/**
* Used by clients to specify the View dimensions.
*
* @param idx
*            Index of the View.
* @param w
*            Width of the parent View.
* @param h
*            Height of the parent View.
* @param dims
*            dims[0] should be set to View width. dims[1] should be set to View height.
*/
public void getViewSize(int idx, int w, int h, int[] dims);
}
}

Step 4 : create java class and named it as SimpleGestureFilter.java , and this class is responsible for detecting swipe motion events.

package com.shyam.smelsample.common;

import android.app.Activity;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;

public class SimpleGestureFilter extends SimpleOnGestureListener{

public final static int SWIPE_UP    = 1;
public final static int SWIPE_DOWN  = 2;
public final static int SWIPE_LEFT  = 3;
public final static int SWIPE_RIGHT = 4;

public final static int MODE_TRANSPARENT = 0;
public final static int MODE_SOLID       = 1;
public final static int MODE_DYNAMIC     = 2;

private final static int ACTION_FAKE = -13; //just an unlikely number
private int swipe_Min_Distance = 180;
private int swipe_Max_Distance = 300;
private int swipe_Min_Velocity = 100;

private int mode             = MODE_DYNAMIC;
private boolean running      = true;
private boolean tapIndicator = false;

private Activity context;
private GestureDetector detector;
private SimpleGestureListener listener;

public SimpleGestureFilter(Activity context,SimpleGestureListener sgl) {

this.context = context;
this.detector = new GestureDetector(context, this);
this.listener = sgl;
}

public void onTouchEvent(MotionEvent event){

if(!this.running)
return; 

boolean result = this.detector.onTouchEvent(event);

if(this.mode == MODE_SOLID)
event.setAction(MotionEvent.ACTION_CANCEL);
else if (this.mode == MODE_DYNAMIC) {

if(event.getAction() == ACTION_FAKE)
event.setAction(MotionEvent.ACTION_UP);
else if (result)
event.setAction(MotionEvent.ACTION_CANCEL);
else if(this.tapIndicator){
event.setAction(MotionEvent.ACTION_DOWN);
this.tapIndicator = false;
}

}
//else just do nothing, it's Transparent
}

public void setMode(int m){
this.mode = m;
}

public int getMode(){
return this.mode;
}

public void setEnabled(boolean status){
this.running = status;
}

public void setSwipeMaxDistance(int distance){
this.swipe_Max_Distance = distance;
}

public void setSwipeMinDistance(int distance){
this.swipe_Min_Distance = distance;
}

public void setSwipeMinVelocity(int distance){
this.swipe_Min_Velocity = distance;
}

public int getSwipeMaxDistance(){
return this.swipe_Max_Distance;
}

public int getSwipeMinDistance(){
return this.swipe_Min_Distance;
}

public int getSwipeMinVelocity(){
return this.swipe_Min_Velocity;
}

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {

final float xDistance = Math.abs(e1.getX() - e2.getX());
final float yDistance = Math.abs(e1.getY() - e2.getY());

if(xDistance > this.swipe_Max_Distance || yDistance > this.swipe_Max_Distance)
return false;

velocityX = Math.abs(velocityX);
velocityY = Math.abs(velocityY);
boolean result = false;

if(velocityX > this.swipe_Min_Velocity && xDistance > this.swipe_Min_Distance){
if(e1.getX() > e2.getX()) // right to left
this.listener.onSwipe(SWIPE_LEFT);
else
this.listener.onSwipe(SWIPE_RIGHT);

result = true;
}
else if(velocityY > this.swipe_Min_Velocity && yDistance > this.swipe_Min_Distance){
if(e1.getY() > e2.getY()) // bottom to up
this.listener.onSwipe(SWIPE_UP);
else
this.listener.onSwipe(SWIPE_DOWN);

result = true;
}

return result;
}

@Override
public boolean onSingleTapUp(MotionEvent e) {
this.tapIndicator = true;
return false;
}

@Override
public boolean onDoubleTap(MotionEvent arg) {
this.listener.onDoubleTap();;
return true;
}

@Override
public boolean onDoubleTapEvent(MotionEvent arg) {
return true;
}

@Override
public boolean onSingleTapConfirmed(MotionEvent arg) {

if(this.mode == MODE_DYNAMIC){        // we owe an ACTION_UP, so we fake an
arg.setAction(ACTION_FAKE);      //action which will be converted to an ACTION_UP later.
this.context.dispatchTouchEvent(arg);
}  

return false;
}

public static interface SimpleGestureListener{
void onSwipe(int direction);
void onDoubleTap();
}

}

Step 5 : create a java class and named it as CategoriesDTO.java

package com.shyam.smelsample.dto;

import java.util.ArrayList;

public class CategoriesDTO {
private String title;
private int id;
private int parentId;
private ArrayList<Integer> childrenIds;

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

public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}

public int getParentId() {
return parentId;
}
public void setParentId(int parentId) {
this.parentId = parentId;
}

public ArrayList<Integer> getChildrenIds() {
return childrenIds;
}
public void setChildrenIds(ArrayList<Integer> childrenIds) {
this.childrenIds = childrenIds;
}
}

Step 6 : Now it's turn to create Activity class, so create a java class and named it as MainActivity.java

package com.shyam.smelsample.gui;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import com.shyam.slidingmenuwithexpandablelistexample.R;
import com.shyam.smelsample.common.SimpleGestureFilter;
import com.shyam.smelsample.common.SimpleGestureFilter.SimpleGestureListener;
import com.shyam.smelsample.dto.CategoriesDTO;
import com.slidingview.MyHorizontalScrollView;
import com.slidingview.MyHorizontalScrollView.SizeCallback;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.ExpandableListView.OnChildClickListener;
import android.widget.ExpandableListView.OnGroupClickListener;
import android.widget.ExpandableListView.OnGroupCollapseListener;
import android.widget.ExpandableListView.OnGroupExpandListener;
import android.widget.RelativeLayout.LayoutParams;

public class MainActivity extends Activity implements SimpleGestureListener
{
MyHorizontalScrollView scrollView;
View menu,app,btnSlide;
ExpandableListView categoryMenulistView;
private boolean menuOut = false;
HashMap<String, List<CategoriesDTO>> expListDataChild;
ArrayList<Integer> selectedData;
ArrayList<CategoriesDTO> categoryObjectsParentList;
ExpandableListAdapter listAdapter;
private SimpleGestureFilter detector; 
int idCounter = 10;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LayoutInflater inflater = LayoutInflater.from(this);
scrollView = (MyHorizontalScrollView) inflater.inflate(R.layout.activity_main, null);
setContentView(scrollView);

// Detect touched area 
detector = new SimpleGestureFilter(this,this);

menu = inflater.inflate(R.layout.menu_drawer, null);
app = inflater.inflate(R.layout.main_application, null);

btnSlide = app.findViewById(R.id.slideBtn);

btnSlide.setOnClickListener(new ClickListenerForScrolling(scrollView, menu));

categoryMenulistView = (ExpandableListView) menu.findViewById(R.id.categorylist);

selectedData = new ArrayList<Integer>();
prepareExpandableListData();
listAdapter = new ExpandableListAdapter(this, categoryObjectsParentList, expListDataChild);
categoryMenulistView.setAdapter(listAdapter);
// Listview Group click listener
categoryMenulistView.setOnGroupClickListener(new OnGroupClickListener() {

@Override
public boolean onGroupClick(ExpandableListView parent, View v,
int groupPosition, long id) {
ImageView groupImageView = (ImageView)v.findViewById(R.id.groupImageView);
int clickedId = categoryObjectsParentList.get(groupPosition).getId();
//check here is any of this childs are in selected data, if selected remove them and its parent
//if not selected, add this id to selected data.
ArrayList<Integer> childIds =categoryObjectsParentList.get(groupPosition).getChildrenIds();
boolean childrenSelected = checkChildrenSelected(childIds);
boolean flagClicked = iterateSelectedData(clickedId); // if already selected, ID will be removed from list.
if(flagClicked)
{
groupImageView.setBackgroundResource(R.color.thickgray);
}
else
{
if(childrenSelected)
{
groupImageView.setBackgroundResource(R.color.thickgray);
}
else
{
groupImageView.setBackgroundResource(R.color.sky_blue);
selectedData.add(clickedId);
}

}

return false;
}
});

// Listview Group expanded listener
categoryMenulistView.setOnGroupExpandListener(new OnGroupExpandListener() {

@Override
public void onGroupExpand(int groupPosition) {

}
});

// Listview Group collasped listener
categoryMenulistView.setOnGroupCollapseListener(new OnGroupCollapseListener() {
@Override
public void onGroupCollapse(int groupPosition) {

}
});

// Listview on child click listener
categoryMenulistView.setOnChildClickListener(new OnChildClickListener() {

@Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
View groupView = parent.getExpandableListAdapter().getGroupView(groupPosition, true, null, (ViewGroup) v.getParent());
ImageView groupCatIcon = (ImageView) groupView.findViewById(R.id.groupImageView);

ImageView childImageView = (ImageView)v.findViewById(R.id.childImageView);
int childClickId = expListDataChild.get(categoryObjectsParentList.get(groupPosition).getTitle()).get(childPosition).getId();
int parentId =  expListDataChild.get(categoryObjectsParentList.get(groupPosition).getTitle()).get(childPosition).getParentId();
ArrayList<Integer> childIds =categoryObjectsParentList.get(groupPosition).getChildrenIds();
boolean flagClicked = iterateSelectedData(childClickId);
if(flagClicked)
{

childImageView.setBackgroundResource(R.color.lightgray);
boolean counterFlag = checkOtherSiblingsClicked(childIds);
if(counterFlag == true)//remove parent id from selected data
{
removeParentId(parentId);
groupCatIcon.setBackgroundResource(R.color.thickgray);

}
else // add parent id in selected data
{
selectedData.add(parentId);
groupCatIcon.setBackgroundResource(R.color.sky_blue);

}

}
else
{
childImageView.setBackgroundResource(R.color.sky_blue);
selectedData.add(childClickId);

removeParentId(parentId);
groupCatIcon.setBackgroundResource(R.color.thickgray);
}
listAdapter.notifyDataSetChanged();
return false;
}

});

final View[] children = new View[] { menu, app };
// Scroll to app (view[1]) when layout finished.
int scrollToViewIdx = 1;
scrollView.initViews(children, scrollToViewIdx, new SizeCallbackForMenu(btnSlide));
}
public void removeParentId(int parentId)
{
for(int i=0;i<selectedData.size();i++)
{

if (selectedData.get(i) == parentId)
{
selectedData.remove(i);

break;
}
else
{

}
}
}
private boolean iterateSelectedData(int clickedId)
{
Boolean flagClicked = false;
for(int i=0;i<selectedData.size();i++)
{

if (selectedData.get(i) == clickedId)
{
flagClicked = true;
selectedData.remove(i);
break;
}
else
{
flagClicked = false;

}
}
return flagClicked;

}
protected Boolean checkChildrenSelected(ArrayList<Integer> childIds) {
Boolean flagClicked = false;
int selectedDataSize = selectedData.size();

for(int i=0;i<selectedDataSize;i++)
{
int SelectedId = 0;
if(selectedData.size()>0)
{
SelectedId = selectedData.get(0);
}

int childsDataSize = childIds.size();
for(int j=0;j<childsDataSize;j++)
{
if (childIds.get(j) == SelectedId)
{
flagClicked = true;
selectedData.remove(0);
break;
}

}
}
return flagClicked;
}
private boolean checkOtherSiblingsClicked(ArrayList<Integer> childIds) {
boolean flag = false;
for(int i=0;(i<childIds.size() && !flag);i++)
{
int siblingId = childIds.get(i);

for(int j=0;j<selectedData.size();j++)
{
if(siblingId == selectedData.get(j))//remove parent id from selected data
{
flag = true;
break;
}
else
{
flag = false;
}
}
}

return flag;
}
private void prepareExpandableListData() {
expListDataChild = new HashMap<String,List<CategoriesDTO>>();
categoryObjectsParentList = new ArrayList<CategoriesDTO>();

//creating 5 parents
for(int i=1;i<=5;i++)
{
CategoriesDTO dto = new CategoriesDTO();
dto.setId(i);
dto.setTitle("Parent No-"+i);
dto.setParentId(-1);


if(i % 2 == 0)
{
//creating 3 children to each even number parent
ArrayList<CategoriesDTO> childrenList = new ArrayList<CategoriesDTO>();
ArrayList<Integer> childIds = new ArrayList<Integer>();

for(int j=1;j<=3;j++)
{
CategoriesDTO childdto = new CategoriesDTO();


childdto.setId(idCounter);
childdto.setTitle("children No-"+j);
childdto.setParentId(i);
childrenList.add(childdto);
childIds.add(idCounter);
idCounter++;
}
dto.setChildrenIds(childIds);
expListDataChild.put(dto.getTitle(), childrenList);
}
else
{
dto.setChildrenIds(new ArrayList<Integer>());
expListDataChild.put(dto.getTitle(),new ArrayList<CategoriesDTO>());

}
categoryObjectsParentList.add(dto); //adding parent to ArrayList
}

}
private void openDrawerMenu()
{
// Scroll to 0 to reveal menu
int left = 0;
scrollView.smoothScrollTo(left, 0);
menuOut = true;
}
public void closeDrawerFunction(View v)
{

int menuWidth = menu.getMeasuredWidth();
// Scroll to menuWidth so menu isn't on screen.
menuOut = false;
int left = menuWidth;

scrollView.smoothScrollTo(left, 0);

}

/**
* Helper for examples with a HSV that should be scrolled by a menu View's width.
*/
class ClickListenerForScrolling implements OnClickListener {
HorizontalScrollView scrollView;
View menu;

RelativeLayout categoryRelView;
/**
* Menu must NOT be out/shown to start with.
*/


public ClickListenerForScrolling(HorizontalScrollView scrollView, View menu) {
super();
this.scrollView = scrollView;
this.menu = menu;

categoryRelView = (RelativeLayout)menu.findViewById(R.id.category_relView);

}

@Override
public void onClick(View v) {
int menuWidth = menu.getMeasuredWidth();

// Ensure menu is visible
menu.setVisibility(View.VISIBLE);

if (!menuOut) {
// Scroll to 0 to reveal menu
int left = 0;
scrollView.smoothScrollTo(left, 0);


} else {
// Scroll to menuWidth so menu isn't on screen.
int left = menuWidth;

scrollView.smoothScrollTo(left, 0);

}
menuOut = !menuOut;
}
}

/**
* Helper that remembers the width of the 'slide' button, so that the 'slide' button remains in view, even when the menu is
* showing.
*/
class SizeCallbackForMenu implements SizeCallback {
int btn1width;
View btn1;
LayoutParams lp ;
public SizeCallbackForMenu(View btnSlide) {
super();
this.btn1 = btnSlide;

}

@Override
public void onGlobalLayout() {
lp = (LayoutParams) btn1.getLayoutParams();
btn1width = btn1.getMeasuredWidth()+lp.leftMargin+lp.rightMargin;
}

@Override
public void getViewSize(int idx, int w, int h, int[] dims) {
dims[0] = w;
dims[1] = h;
final int menuIdx = 0;
if (idx == menuIdx) {
dims[0] = w - btn1width;
}
}
}

public class ExpandableListAdapter extends BaseExpandableListAdapter {

private Context _context;
private ArrayList<CategoriesDTO> catObjectsList;
private HashMap<String,List<CategoriesDTO>> catChildObjectsData;
public ExpandableListAdapter(Context context, List<String> listDataHeader,
HashMap<String, List<String>> listChildData) {
this._context = context;
}

public ExpandableListAdapter(Context context,ArrayList<CategoriesDTO> categoryObjectsList,
HashMap<String, List<CategoriesDTO>> expListDataChild2) {
this._context = context;
this.catObjectsList = categoryObjectsList;
this.catChildObjectsData = expListDataChild2;
}

@Override
public Object getChild(int groupPosition, int childPosititon) {
return this.catChildObjectsData.get(this.catObjectsList.get(groupPosition).getTitle()).get(childPosititon).getTitle();
}
public Object getChildObject(int groupPosition, int childPosititon) {
return this.catChildObjectsData.get(this.catObjectsList.get(groupPosition).getTitle()).get(childPosititon);
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}

@Override
public View getChildView(int groupPosition, final int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
CategoriesDTO dto = (CategoriesDTO) getChildObject(groupPosition, childPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) this._context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.custom_expandable_menu_child, null);

}
ImageView catChildIcon = (ImageView)convertView.findViewById(R.id.childImageView);
boolean flagClicked = iterateSelectedData(dto.getId());
if(flagClicked)
{
catChildIcon.setBackgroundResource(R.color.sky_blue);
}
else
{
catChildIcon.setBackgroundResource(R.color.mediumgray);  
}
TextView txtListChild = (TextView) convertView.findViewById(R.id.lblListItem);
String childTitle = Html.fromHtml(dto.getTitle()).toString();


txtListChild.setText(childTitle);

return convertView;
}
private boolean iterateSelectedData(int clickedId)
{
Boolean flagClicked = false;
for(int i=0;i<selectedData.size();i++)
{

if (selectedData.get(i) == clickedId)
{
flagClicked = true;

break;
}
else
{
flagClicked = false;

}
}
return flagClicked;

}
@Override
public int getChildrenCount(int groupPosition) {
return this.catChildObjectsData.get(this.catObjectsList.get(groupPosition).getTitle()).size();
}

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

@Override
public int getGroupCount() {
int count = 0;
for(int i=0;i<catObjectsList.size();i++)
{
CategoriesDTO dto = catObjectsList.get(i);
if(dto.getParentId()==-1)
{
count++;
}
}
return count;
}

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

@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
String headerTitle = (String) getGroup(groupPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) this._context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.custom_expandable_menu_group, null);
}

TextView lblListHeader = (TextView) convertView.findViewById(R.id.lblListHeader);
ImageView catIcon = (ImageView)convertView.findViewById(R.id.groupImageView);

boolean flagClicked = iterateSelectedData(catObjectsList.get(groupPosition).getId());
if(flagClicked)
{
catIcon.setBackgroundResource(R.color.sky_blue);
}
else
{
catIcon.setBackgroundResource(R.color.thickgray);  
}
String parentTitle = Html.fromHtml(headerTitle).toString();
lblListHeader.setText(parentTitle);

return convertView;
}

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

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

}
@Override
public boolean dispatchTouchEvent(MotionEvent me){
// Call onTouchEvent of SimpleGestureFilter class
this.detector.onTouchEvent(me);
return super.dispatchTouchEvent(me);
}
@Override
public void onSwipe(int direction) {
switch (direction) {

case SimpleGestureFilter.SWIPE_RIGHT : 
if(!menuOut)//if menu drawer is not opened
{
openDrawerMenu();
}
break;
case SimpleGestureFilter.SWIPE_LEFT : 
if(menuOut)//if menu drawer is opened
{
closeDrawerFunction(null);
}

break;
case SimpleGestureFilter.SWIPE_DOWN : 

break;
case SimpleGestureFilter.SWIPE_UP :  

break;

}
}
@Override
public void onDoubleTap() {

}
}

Step 7 : modify the android manifest file with below : 

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.shyam.slidingmenuwithexpandablelistexample"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="11"
        android:targetSdkVersion="21" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.shyam.smelsample.gui.MainActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Thats it! Now run the program and see the application.
Cheers....

Click Here For Complete Code