C’mon…Android’s SlidingDrawer is a pretty neat & handy component. It does what its supposed to: open/close a drawer revealing with it tucked away icons or additional view components.

Its a pretty smart way of:

  • Intuitive use of a well-known archetype everybody knows: a drawer which open/close..simple!
  • Saves and maximizes use of screen real estate
  • Visually appealing.

The Problem:
BUT…..yes you had it coming, sometimes its default behavior is not what you would expect! The default behaviour of the SlidingDrawer component is to maximize to a height of the position of the last component on the screen. But if the last component is at the very bottom, then the SlidingDrawer will not be apparently visible!

In the screenshot immediately below,  I want the Help SlidingDrawer to overlap the ListView when maximized, except the ListView is blocking its visibility!..I know annoying Droid!

The Solution:

Manipulating Android’s View layer to hide/reveal components!
listview – a reference to the ListView component declared in your XML-layout file.
helpDrawer – a reference to the SlidingDrawer component in our XML-layout file.

         // SlidingDrawer
	helpDrawer = (SlidingDrawer) this.findViewById(R.id.helpdrawer);

        // Open Handler
	helpDrawer.setOnDrawerOpenListener(new OnDrawerOpenListener()
	{
		@Override
		public void onDrawerOpened()
		{
			 listView.setVisibility(ListView.GONE);
		}
	});

	// Closing Handler
	helpDrawer.setOnDrawerCloseListener(new OnDrawerCloseListener()
	{
		@Override
		public void onDrawerClosed()
			{
				 listView.setVisibility(ListView.VISIBLE);
			}
	});

Initially Minimized and Closed state:

Open and Maximized State:

For making the example more clear:

Download: TestSlidingDrawerOverList.zip

File: main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content">

	<ListView
		android:id="@+id/list_journal"
		android:layout_width="fill_parent"
		android:layout_height="365dip" />

	<SlidingDrawer
		android:id="@+id/slidingDrawer"
		android:handle="@+id/drawerHandle"
		android:content="@+id/contentLayout"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content">

		<ImageView
			android:id="@+id/drawerHandle"
			android:src="@drawable/help_tab_selector"
			android:layout_width="fill_parent"
			android:layout_height="wrap_content">
		</ImageView>

		<LinearLayout
			xmlns:android="http://schemas.android.com/apk/res/android"
			android:id="@+id/contentLayout"
			android:gravity="center"
			android:layout_width="fill_parent"
			android:layout_height="wrap_content"
			android:background="@drawable/bg">
			<ImageView
				android:src="@drawable/icon"
				android:layout_width="fill_parent"
				android:layout_height="wrap_content"
				android:layout_gravity="center">
			</ImageView>
		</LinearLayout>
	</SlidingDrawer>
</LinearLayout>

File: list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:id="@+id/list_item"
	android:gravity="center"
	android:textColor="@color/white"
	android:textAppearance="?android:attr/textAppearanceMedium"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content">
</TextView>

File: Main.java

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

import android.app.Activity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.SlidingDrawer;
import android.widget.SlidingDrawer.OnDrawerCloseListener;
import android.widget.SlidingDrawer.OnDrawerOpenListener;

public class Main extends Activity implements OnDrawerOpenListener,
		OnDrawerCloseListener {

	private ListView listView;
	private SlidingDrawer slidingDrawer;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		// Set the View Layer
		setContentView(R.layout.main);
		
                // Generate some data
		List<String> data= getData();

		// Get reference to ListView
		listView = (ListView) this.findViewById(R.id.list_journal);
                
                 // Create a adapter for the ListView
		ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, R.layout.list_item, data);
 
                //Set the listview adapter
		listView.setAdapter(arrayAdapter);

		// Get reference to SlidingDrawer
		slidingDrawer = (SlidingDrawer) this.findViewById(R.id.slidingDrawer);

                //Listen for open event
		slidingDrawer.setOnDrawerOpenListener(this);

                // Listen for close event
		slidingDrawer.setOnDrawerCloseListener(this);
	}
	
	/**
	 * Get some data
	 * @return
	 */
	private List<String> getData()
	{
		List<String> data= new ArrayList<String>();
		for( int i= 0; i < 20; i++)
		{
			data.add( String.valueOf(i));
		}
		return data;
	}

	@Override
	public void onDrawerOpened() {
                // Hide listview 
		listView.setVisibility(ListView.GONE);
	}

	@Override
	public void onDrawerClosed() {
                // now make it visible again           
		listView.setVisibility(ListView.VISIBLE);
	}
}

State: Close - ListView over SlidingDrawer

State Open: SlidingDrawer over ListView

Viola!!!

It’s always helpful to have an alternate solution depending on how
your views are layed out.

An alternate solution has been provided by Mendelt Siebenga:

“The reason for the strange behavior with the sliding drawer isn’t the sliding drawer itself but the linearlayout. LinearLayouts can’t display overlapping views. If you use a framelayout as the parent of the listview and the slidingdrawer your problem is solved too.”

Download: http://www.filefactory.com/file/cb4f522/n/TestSlidingDrawerOverList.zip
File : main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content">
	
	<LinearLayout
		android:orientation="vertical"
		android:layout_width="fill_parent"
		android:layout_height="fill_parent">		

		<TextView
			android:layout_width="fill_parent"
			android:layout_height="wrap_content"
			android:text="Some extra text" />

		<ListView
			android:id="@+id/list_journal"
			android:layout_width="fill_parent"
			android:layout_height="365dip" />
	
	</LinearLayout>

	<SlidingDrawer
		android:id="@+id/slidingDrawer"
		android:handle="@+id/drawerHandle"
		android:content="@+id/contentLayout"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content">

		<ImageView
			android:id="@+id/drawerHandle"
			android:src="@drawable/help_tab_selector"
			android:layout_width="fill_parent"
			android:layout_height="wrap_content">
		</ImageView>

		<LinearLayout
			xmlns:android="http://schemas.android.com/apk/res/android"
			android:id="@+id/contentLayout"
			android:gravity="center"
			android:layout_width="fill_parent"
			android:layout_height="wrap_content"
			android:background="@drawable/bg">
			<ImageView
				android:src="@drawable/icon"
				android:layout_width="fill_parent"
				android:layout_height="wrap_content"
				android:layout_gravity="center">
			</ImageView>
		</LinearLayout>
	</SlidingDrawer>
</FrameLayout>

File: Main.java

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

import android.app.Activity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.SlidingDrawer;
import android.widget.SlidingDrawer.OnDrawerCloseListener;
import android.widget.SlidingDrawer.OnDrawerOpenListener;

public class Main extends Activity {

	private ListView listView;
//	private SlidingDrawer slidingDrawer;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		// Set the View Layer
		setContentView(R.layout.main);
		
		List<String> data= getData();

		// Get reference to ListView
		listView = (ListView) this.findViewById(R.id.list_journal);
		ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, R.layout.list_item, data);
		listView.setAdapter(arrayAdapter);

		// Get reference to SlidingDrawer
//		slidingDrawer = (SlidingDrawer) this.findViewById(R.id.slidingDrawer);
//		slidingDrawer.setOnDrawerOpenListener(this);
//		slidingDrawer.setOnDrawerCloseListener(this);
	}
	
	/**
	 * Get some data
	 * @return
	 */
	private List<String> getData()
	{
		List<String> data= new ArrayList<String>();
		for( int i= 0; i < 20; i++)
		{
			data.add( String.valueOf(i));
		}
		return data;
	}

//	@Override
//	public void onDrawerOpened() {
//		listView.setVisibility(ListView.GONE);
//	}
//
//	@Override
//	public void onDrawerClosed() {
//		listView.setVisibility(ListView.VISIBLE);
//	}

}