Android - Create Sliding Panel like Gmail app on Tablet

    In my previous post, I have presented the "ListView with Letter Icon" like Gmail app. Therefore, in Tablet, this app also has an interesting UI with "partial sliding panel":
    This is not NavigationDrawer, it is SlidingPaneLayout. In this post, I will provide some solutions to custom this widget to make a layout like Gmail!

Original Sliding Panel

    By original, this widget has 2 children layouts, the first one is left panel and the other one is the main panel. A simple layout will be like this:
activity_main.xml
<android.support.v4.widget.SlidingPaneLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/sliding_pane_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    
    <TextView
        android:layout_width="230dp"
        android:layout_height="match_parent"
        android:background="@android:color/holo_blue_dark"
        android:text="Panel 1" />

    
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/holo_green_dark"
        android:text="Panel 2" />
</android.support.v4.widget.SlidingPaneLayout>
    After running, we have this result:

NOTE: In some devices, when the left panel expanded, the main layout may be turned to gray:
    To avoiding this matter, please add this code to change the fade color to transperant:
SlidingPaneLayout slidingPaneLayout = (SlidingPaneLayout) findViewById(R.id.sliding_pane_layout);
assert slidingPaneLayout != null;
slidingPaneLayout.setSliderFadeColor(Color.TRANSPARENT);

Partial Sliding Panel

Now we'll make the main panel partially visible when collapsed. Very simple: adding margin to the main panel:
activity_main.xml
<android.support.v4.widget.SlidingPaneLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/sliding_pane_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="250dp"
        android:layout_height="match_parent"
        android:background="@android:color/holo_blue_dark"
        android:text="Panel 1" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginLeft="60dp"
        android:background="@android:color/holo_green_dark"
        android:text="Panel 2" />
</android.support.v4.widget.SlidingPaneLayout>
    We'll have this result:

Handling Panel expand/collapse event

    To handling the SlidingPanelLayout event, make your Activity/Fragment implements SlidingPaneLayout.PanelSlideListener and overriding these 3 methods:
  • onPanelOpened(): Called when the left panel completely open.
  • onPanelClosed(): Called when the lef panel completely collapsed. The panel is now guaranteed to be interactive. It may now obscure other views in the layout.
  • onPanelSlide():Called when a sliding panel's position changes.

Complex data: an example

    Now, I will provide a project with 2 SlidingPanelLayout children is ListViews. The activity layout wille be like:
activity_main.xml
<android.support.v4.widget.SlidingPaneLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/sliding_pane_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="250dp"
        android:layout_height="match_parent"
        android:background="#66b3ff"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#0000ff"
            android:gravity="center"
            android:padding="10dp"
            android:text="Continents"
            android:textColor="#ffffff" />

        <ListView
            android:id="@+id/left_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginLeft="60dp"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#00d0f0"
            android:gravity="center"
            android:padding="10dp"
            android:text="Countries"
            android:textColor="#ffffff" />

        <ListView
            android:id="@+id/main_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#0099C2" />

    </LinearLayout>
</android.support.v4.widget.SlidingPaneLayout>
    In the programmatically code, set adapter for each ListView, handling their item click event and show/hide the left panel ListView when it's expand/collapse, we have this full code:
MainActivity.java
package info.devexchanges.slidingpanel;

import android.graphics.Color;
import android.support.v4.widget.SlidingPaneLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements SlidingPaneLayout.PanelSlideListener {

    private ListView leftListView;
    private ListView mainListView;
    private String[] asiaCountries;
    private String[] europeCountries;
    private String[] africaCountries;
    private String[] continents;
    private static final String[] NO_DATA = {};
    private ArrayAdapter<String> mainPanelAdapter;
    private String TAG = MainActivity.class.getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        leftListView = (ListView) findViewById(R.id.left_list);
        mainListView = (ListView) findViewById(R.id.main_list);

        SlidingPaneLayout slidingPaneLayout = (SlidingPaneLayout) findViewById(R.id.sliding_pane_layout);
        assert slidingPaneLayout != null;
        slidingPaneLayout.setPanelSlideListener(this);
        slidingPaneLayout.setSliderFadeColor(Color.TRANSPARENT);

        //get string arrays resource
        asiaCountries = getResources().getStringArray(R.array.asia);
        europeCountries = getResources().getStringArray(R.array.europe);
        africaCountries = getResources().getStringArray(R.array.africa);
        continents = getResources().getStringArray(R.array.continent);

        //set listviews adapter
        ArrayAdapter<String> leftPaneAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, continents);
        leftListView.setAdapter(leftPaneAdapter);
        mainPanelAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, asiaCountries);
        mainListView.setAdapter(mainPanelAdapter);

        //handling left panel listview item click event
        leftListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (position == 0) {
                    setMainAdapter(asiaCountries);
                } else if (position == 1) {
                    setMainAdapter(europeCountries);
                } else if (position == 2) {
                    setMainAdapter(africaCountries);
                } else {
                    setMainAdapter(NO_DATA);
                    Toast.makeText(MainActivity.this, "No data!", Toast.LENGTH_SHORT).show();
                }
            }
        });

        //handling main panel listview item click event
        mainListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                String item = (String) parent.getItemAtPosition(position);
                Toast.makeText(MainActivity.this, "You selectd: " + item, Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void setMainAdapter(String[] strings) {
        mainPanelAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, strings);
        mainListView.setAdapter(mainPanelAdapter);
    }

    @Override
    public void onPanelSlide(View panel, float slideOffset) {
        Log.i(TAG, "onPanelSlide: " + slideOffset);
    }

    @Override
    public void onPanelOpened(View panel) {
        Log.i(TAG, "onPanelOpened");
        leftListView.setVisibility(View.VISIBLE);
    }

    @Override
    public void onPanelClosed(View panel) {
        Log.i(TAG, "onPanelClosed");
        leftListView.setVisibility(View.GONE);
    }
}
     And this is the final result:

Conclusions

Through this post, I hope readers can learned once more widget in Android SDK to make a interesting layout (like Gmail application). You can take a glance at my previous post (about making ListView with letter icon on the left side). Moreover, let subscribe my blog to get newest tutorials. Finally, you can download full project on @Github.

Share


Previous post
« Prev Post
Next post
Next Post »