Android Side Menu Bar Example
Below the example for Android side Navigation like Facebook side Navigation.
This is simple example only. If you want to modify as per as your requirement you can change it.
I really like Side Navigation pattern and I think it is especially useful on mobile devices with small screen, but it’s pretty important that the user experience that comes with it has to be carefully crafted so it doesn’t cause user frustration and confusion.
HorizontalSideScrollVie.java
package
com.vijay.ex;
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 HorizontalSideScrollView extends
HorizontalScrollView {
public
HorizontalSideScrollView(Context context, AttributeSet attrs, int
defStyle) {
super(context,
attrs, defStyle);
init(context);
}
public
HorizontalSideScrollView(Context context, AttributeSet attrs) {
super(context,
attrs);
init(context);
}
public
HorizontalSideScrollView(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 HorizontalSideScrollView
me = HorizontalSideScrollView.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);
}
}
HorzScrollSideMenuActivit.java
package
com.vijay.ex;
import java.util.Date;
import
com.vijay.ex.HorizontalSideScrollView.SizeCallback;
import
android.app.Activity;
import android.content.Context;
import
android.os.Bundle;
import
android.os.Handler;
import android.view.LayoutInflater;
import
android.view.View;
import
android.view.View.OnClickListener;
import
android.view.ViewGroup;
import
android.widget.AdapterView;
import
android.widget.AdapterView.OnItemClickListener;
import
android.widget.ArrayAdapter;
import
android.widget.HorizontalScrollView;
import
android.widget.ImageView;
import
android.widget.ListView;
import
android.widget.Toast;
public class
HorzScrollSideMenuActivity extends Activity {
HorizontalSideScrollView scrollView;
View menuView;
View applicationView;
ImageView btnSlide;
boolean menuOut = false;
Handler handler = new
Handler();
int btnWidth;
String[] str= {"Android1.1","Android2.1","Android2.2","Android3.0","Android4.0","Android4.2","http://www.android-ever.com/","http://www.iamvijayakumar.blogspot.com/"};
String[] developerSites= {"Developer Sites","Local
Ref Site","Settings","Accounts","http://www.android-ever.com/","http://www.iamvijayakumar.blogspot.com/","Settings","Accounts","http://www.iamvijayakumar.blogspot.com/","http://www.iamvijayakumar.blogspot.com/"};
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LayoutInflater inflater = LayoutInflater.from(this);
scrollView =
(HorizontalSideScrollView) inflater.inflate(R.layout.horz_sidemenu_activity_layout, null);
setContentView(scrollView);
menuView =
inflater.inflate(R.layout.side_menu, null);
applicationView =
inflater.inflate(R.layout.mainapplication_layout, null);
ViewGroup tabBar = (ViewGroup) applicationView.findViewById(R.id.tabBar);
ListView listView = (ListView) applicationView.findViewById(R.id.list);
ArrayAdapter< String> adapter = new
ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, str);
listView.setAdapter(adapter);
ListView listView1 = (ListView) menuView.findViewById(R.id.list);
ArrayAdapter< String>
devSiteadapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, developerSites);
listView1.setAdapter(devSiteadapter);
btnSlide =
(ImageView) tabBar.findViewById(R.id.BtnSlide);
btnSlide.setOnClickListener(new
ClickListenerForScrolling(scrollView, menuView));
final
View[] children = new View[] { menuView, applicationView };
int
scrollToViewIdx = 1;
scrollView.initViews(children,
scrollToViewIdx, new SizeCallbackForMenu(btnSlide));
listView1.setOnItemClickListener(new
OnItemClickListener() {
@Override
public void
onItemClick(AdapterView<?> arg0, View arg1, int
position,
long
arg3) {
Toast.makeText(HorzScrollSideMenuActivity.this, "Side
Menu Clicked Item : "+developerSites[position],
Toast.LENGTH_SHORT).show();
}
});
listView.setOnItemClickListener(new
OnItemClickListener() {
@Override
public void
onItemClick(AdapterView<?> arg0, View arg1, int
position,
long
arg3) {
Toast.makeText(HorzScrollSideMenuActivity.this, "Clicked
Item : "+str[position],
Toast.LENGTH_SHORT).show();
}
});
}
/**
* Helper for examples with a HSV that
should be scrolled by a menu View's width.
*/
static class ClickListenerForScrolling
implements OnClickListener {
HorizontalScrollView scrollView;
View menu;
/**
* Menu must NOT be out/shown to start
with.
*/
boolean menuOut = false;
public ClickListenerForScrolling(HorizontalScrollView
scrollView, View menu) {
super();
this.scrollView =
scrollView;
this.menu =
menu;
}
@Override
public void
onClick(View v) {
int menuWidth
= menu.getMeasuredWidth();
// Ensure menu
is visible
menu.setVisibility(View.VISIBLE);
if (!menuOut) {
int left
= 0;
scrollView.smoothScrollTo(left,
0);
} else {
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.
*/
static class
SizeCallbackForMenu implements SizeCallback {
int btnWidth;
View btnSlide;
public
SizeCallbackForMenu(View btnSlide) {
super();
this.btnSlide =
btnSlide;
}
@Override
public void
onGlobalLayout() {
btnWidth = btnSlide.getMeasuredWidth();
}
@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 - btnWidth;
}
}
}
}
XML
horz_sidemenu_activity_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<com.vijay.ex.HorizontalSideScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#00ffffff" android:padding="0px"
android:layout_margin="0px"
android:fadingEdge="none" android:fadingEdgeLength="0px"
android:scrollbars="none">
<LinearLayout android:id="@+id/top" android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:orientation="horizontal"
android:background="#ffffffff" android:padding="0px"
android:layout_margin="0px">
</LinearLayout>
</com.vijay.ex.HorizontalSideScrollView>
mainapplication_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/app"
android:layout_width="1dp"
android:layout_height="1dp" android:orientation="vertical" android:background="#ffffff"
android:padding="2px"
android:layout_margin="2px">
<LinearLayout android:id="@+id/tabBar" android:background="#F6CE1E" android:layout_width="fill_parent"
android:layout_height="60dip"
android:orientation="horizontal">
<ImageView android:id="@+id/BtnSlide" android:layout_width="40dip" android:layout_height="wrap_content"
android:padding="0px"
android:layout_margin="0px" android:src="@drawable/left"
/>
<View android:layout_marginLeft="15dip" android:layout_marginRight="15dip"
android:background="#000000" android:layout_width="2dip"
android:layout_height="wrap_content"></View>
<TextView android:textColor="#000000" android:paddingTop="10dip"
android:textSize="8pt" android:text="List Of
Android Version" android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
<View android:background="#000000"
android:layout_width="fill_parent" android:layout_height="2dip"></View>
<ListView android:id="@+id/list" android:paddingTop="10dip"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:background="#25B5F1"
android:cacheColorHint="@android:color/transparent"
android:dividerHeight="2dip" android:divider="#FFFFFF" >
</ListView>
</LinearLayout>
side_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/menu"
android:orientation="vertical"
android:background="#000000" android:layout_width="1dp"
android:layout_height="1dp">
<LinearLayout android:id="@+id/tabBar" android:background="#F6CE1E" android:layout_width="fill_parent"
android:layout_height="60dip"
android:orientation="horizontal">
<TextView android:textColor="#000000" android:paddingTop="10dip"
android:textSize="8pt" android:text="Side
Menu" android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
<ListView android:id="@+id/list" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#25B5F1"
android:cacheColorHint="@android:color/transparent"
android:dividerHeight="2dip" android:divider="#FFFFFF" android:scrollbars="none">
</ListView>
</LinearLayout>