BLOG

iPhone style menu for Android Applications

Wed, 04/18/2012 - 03:17

 

Many times, we want in our android applications, a nice - Iphone style - option menu, unfortunately there is no native widget to do that, but it is fairly easy to emulate it.

One way to do this is by adding a new View programmatically in your current Layout and show it with an animation. Let’s say you have a menu like the one in figure 1 and you want it to look in your app like the one in figure 2.

   

                        Figure 1                                                Figure 2

What we have to do, is create the menu view and add it programmatically, then the only thing left to do is to show and hide the menu.

To do this, we will use two separated animations, menu_slide_left_in.xml and menu_slide_left_out.xml: here are the samples.

menu_slider_left_in.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="-100%p" android:toXDelta="0%p" android:duration="400"/>
</set>


menu_slider_left_out.xml


<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="0%p" android:toXDelta="-100%p" android:duration="400" android:fillBefore="true"/>
</set>


Of course, if we want our menu to look like the iPhone’s menu, we need to also move the main activity, otherwise, the menu will roll over the screen probably over the menu button (what will make it impossible to close it, if we do it exactly as the iPhone version), so we will need also two separated animations for our content view: view_slide_left_in.xml and view_slide_left_out.xml.

view_slide_left_in.xml


<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="0%p" android:toXDelta="80%p" android:duration="400"  />
</set>


view_slide_left_out.xml


<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="50%p" android:toXDelta="0%p" android:duration="200" />
</set>


Nothing fancy, just two animations to translate the content from to 0% of the screen to an 80% of the screen, and the out animation just moves it from a 50% of the screen back to 0%, I will explain later why moving back from 50% instead of 80%.


Explaining these animation a little bit, in the slide in animation, we are saying that our menu will come from a 100% off the screen to an 0% of the screen, that will make our view to appear, in the slide out animation we are saying exactly the opposite, from the start of the screen (0 X) we move it off the screen, but we add a “fillBefore” attribute, this is to ensure that the animation transformation is applied before the animation has started.

Now we need to add the menu to our activity, this is done programmatically, in this example, I am using Relative Layouts, in our Activity Layout we need an specific Layout called “contentPanel” in oder to move our view back and forth, this is how our view should look like.

<?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="fill_parent"
    android:id="@+id/mainPanel">

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/contentPanel">
   
        Content…

    </RelativeLayout>
</RelativeLayout>


Just to help you out a little bit more, here is how the menu should be:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/darkgray"
    android:orientation="vertical" >
    Option Buttons…
</LinearLayout>

Ok, we have everything we need in terms of Layout, now let’s see the code, we will create a new class called MenuView that extends from Activity,this class will have two main methods, showMenu and hideMenu, and a private createMenu,  showMenu will create the menu view if it is not already created…

{syntaxhighlighter brush:java} public class MenuView extends Activity { View menu; public void showMenu() { if (menu == null) { CreateMenu(); } Animation menuAnimation = AnimationUtils.loadAnimation(this, R.anim.menu_slide_left_in); Animation viewAnimation = AnimationUtils.loadAnimation(this, R.anim.view_slide_left_in); final RelativeLayout mainView = (RelativeLayout)findViewById(R.id.contentPanel); AnimationListener animListener = new AnimationListener() { public void onAnimationStart(Animation animation) { // TODO Auto-generated method stub } public void onAnimationRepeat(Animation animation) { // TODO Auto-generated method stub } public void onAnimationEnd(Animation animation) { LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); params.leftMargin = 384; params.rightMargin = mainView.getWidth() + 384; mainView.setLayoutParams(params); } }; viewAnimation.setAnimationListener(animListener); menu.startAnimation(menuAnimation); mainView.startAnimation(viewAnimation); menu.setVisibility(View.VISIBLE); } public void hideMenu() { if (menu == null) { CreateMenu(); } Animation animation = AnimationUtils.loadAnimation(this, R.anim.menu_slide_left_out); Animation viewAnimation = AnimationUtils.loadAnimation(this, R.anim.view_slide_left_out); final RelativeLayout mainView = (RelativeLayout)findViewById(R.id.contentPanel); AnimationListener animListener = new AnimationListener() { public void onAnimationStart(Animation animation) { // TODO Auto-generated method stub } public void onAnimationRepeat(Animation animation) { // TODO Auto-generated method stub } public void onAnimationEnd(Animation animation) { LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); params.leftMargin = 0; mainView.setLayoutParams(params); } }; viewAnimation.setAnimationListener(animListener); mainView.startAnimation(viewAnimation); menu.startAnimation(animation); menu.setVisibility(View.INVISIBLE); } private void CreateMenu() { menu = ((LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.menu, null); menu.setVisibility(View.INVISIBLE); RelativeLayout mainPanel = (RelativeLayout)findViewById(R.id.mainPanel); mainPanel.addView(menu, new RelativeLayout.LayoutParams(400, LayoutParams.FILL_PARENT)); //Bind Buttons to actions } } {/syntaxhighlighter}

Lets explain this methods a little bit:

createMethod: creates a new view using our menu.xml layout, and adds that view to our mainPanel (which is the main RelativeLayout of our activity).

showMenu: creates all IN animations for both the menu and the mainContent, for the viewAnimation, it creates an animation listener, this is because even if we move our layout with an animation, if we don’t change its position, after the animation ends, the moved panel will return to its original place, with an animation Listener, we can use the onAnimationEnd to modify the mainContent position to avoid that issue. Also it makes our menuView VISIBLE.

hideMenu: creates all OUT animations for both menu and the mainContent, and also, for our viewAnimation it creates an animationListener to moving the content Panel back to its original place, after that it makes our menuView INVISIBLE.

 

I hope it helps! Doesn’t hesitate to ask if you have any doubts, event to my email!

.Net Developer
Senior developer interested in multitier architecture, web based, back-end and core app design and development.