Sunday, 23 January 2011

Implementing Dashboard and Action Bar

Action bar and Dashboard are well established Android UI design patterns that are suitable in most Android projects.

See UI design pattern index for more about these patterns.

I have started a project to help developers to get into speed with their project faster. The project aims to collect together code that can be used to implement different UI patterns. I used Google's IO conference Android application as a basis and removed overhead code to make it easier to understand which bits of it are useful.

More details and other projects after the jump


The project I started can be found from Google code website: [update 2012-01-12 As the project I started is now obsolete an there are better ways to implement Dashboard I removed it from Google code. User the DashboardLayout class instead: see this post]

For now the project contains only one Activity which implements both Dashboard and Action bar.



Implementation guidelines

[update: You might want to check out this implementation for DashboardLayout class first: see this post]

It is important that all Android applications support both portrait and landscape mode. While many layout definitions when written correctly adapt automatically to both modes Dashboard layout is not one of them. To make use of the available space in both modes we need to write two separate layout XMLs. As long as we use same layout XML filename and place the filed in correct folders the Android framework will automatically take care of selecting the correct file on runtime.

Example structure for supporting different layouts  in different orientation.



Portrait layout XML

dashboard.xml:

<?xml version="1.0" encoding="utf-8"?>
<!--
    Copyright 2010 Google Inc.
    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.
-->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/home_root"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <LinearLayout style="@style/TitleBar">
        <ImageView style="@style/TitleBarLogo"
            android:contentDescription="@string/description_logo"
            android:src="@drawable/title_logo" />

        <View style="@style/TitleBarSpring" />

        <ImageView style="@style/TitleBarSeparator" />
        <ImageButton style="@style/TitleBarAction"
            android:id="@+id/btn_title_refresh"
            android:contentDescription="@string/description_refresh"
            android:src="@drawable/ic_title_refresh"
            android:onClick="onActionBarButtonClick" />
        <ProgressBar style="@style/TitleBarProgressIndicator"
            android:id="@+id/title_refresh_progress"
            android:visibility="gone" />

        <ImageView style="@style/TitleBarSeparator" />
        <ImageButton style="@style/TitleBarAction"
            android:contentDescription="@string/description_search"
            android:src="@drawable/ic_title_search"
            android:onClick="onActionBarButtonClick" />
    </LinearLayout>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:padding="6dip">
        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1">
            <Button android:id="@+id/action_one_button"
                style="@style/HomeButton"
                android:onClick="onActionOneClick"
                android:text="@string/dashboard_action"
                android:drawableTop="@drawable/dashboard_button_selector"/>
            <Button android:id="@+id/action_two_button"
                style="@style/HomeButton"
                android:onClick="onActionTwoClick"
                android:text="@string/dashboard_action"
                android:drawableTop="@drawable/dashboard_button_selector"/>
        </LinearLayout>

        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1">
            <Button android:id="@+id/action_three_button"
                style="@style/HomeButton"
                android:onClick="onActionThreeClick"
                android:text="@string/dashboard_action"
                android:drawableTop="@drawable/dashboard_button_selector"/>
            <Button android:id="@+id/action_four_button"
                style="@style/HomeButton"
                android:onClick="onActionFourClick"
                android:text="@string/dashboard_action"
                android:drawableTop="@drawable/dashboard_button_selector"/>
        </LinearLayout>

        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1">
            <Button android:id="@+id/action_five_button"
                style="@style/HomeButton"
                android:onClick="onActionFiveClick"
                android:text="@string/dashboard_action"
                android:drawableTop="@drawable/dashboard_button_selector"/>
            <Button android:id="@+id/action_six_button"
                style="@style/HomeButton"
                android:onClick="onActionSixClick"
                android:text="@string/dashboard_action"
                android:drawableTop="@drawable/dashboard_button_selector"/>

        </LinearLayout>
    </LinearLayout>

    <LinearLayout
        android:id="@+id/now_playing_loading"
        android:layout_width="fill_parent"
        android:layout_height="@dimen/now_playing_height"
        android:orientation="horizontal"
        android:background="#eee"
        android:gravity="center">
        <ProgressBar
            style="?android:attr/progressBarStyleSmall"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingRight="6dip"
            android:indeterminate="true"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="@dimen/text_size_small"
            android:text="@string/now_playing_loading"/>
    </LinearLayout>
</LinearLayout>


Landscape layout XML

dashboard.xml:

<?xml version="1.0" encoding="utf-8"?>
<!--
    Copyright 2010 Google Inc.
    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.
-->


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/home_root"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">


    <LinearLayout style="@style/TitleBar">
        <ImageView style="@style/TitleBarLogo"
            android:src="@drawable/title_logo" />


        <View style="@style/TitleBarSpring" />


        <ImageView style="@style/TitleBarSeparator" />
        <ImageButton style="@style/TitleBarAction"
            android:id="@+id/btn_title_refresh"
            android:src="@drawable/ic_title_refresh"
            android:onClick="onActionBarButtonClick" />
        <ProgressBar style="@style/TitleBarProgressIndicator"
            android:id="@+id/title_refresh_progress"
            android:visibility="gone" />


        <ImageView style="@style/TitleBarSeparator" />
        <ImageButton style="@style/TitleBarAction"
            android:src="@drawable/ic_title_search"
            android:onClick="onActionBarButtonClick" />
    </LinearLayout>


    <LinearLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:padding="6dip">
        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1">
            <Button android:id="@+id/action_one_button"
                style="@style/HomeButton"
                android:onClick="onActionOneClick"
                android:text="@string/dashboard_action"
                android:drawableTop="@drawable/dashboard_button_selector"/>
            <Button android:id="@+id/action_two_button"
                style="@style/HomeButton"
                android:onClick="onActionTwoClick"
                android:text="@string/dashboard_action"
                android:drawableTop="@drawable/dashboard_button_selector"/>
            <Button android:id="@+id/action_three_button"
                style="@style/HomeButton"
                android:onClick="onActionThreeClick"
                android:text="@string/dashboard_action"
                android:drawableTop="@drawable/dashboard_button_selector"/>
        </LinearLayout>
    
        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1">
            <Button android:id="@+id/action_four_button"
                style="@style/HomeButton"
                android:onClick="onActionFourClick"
                android:text="@string/dashboard_action"
                android:drawableTop="@drawable/dashboard_button_selector"/>
            <Button android:id="@+id/action_five_button"
                style="@style/HomeButton"
                android:onClick="onActionFiveClick"
                android:text="@string/dashboard_action"
                android:drawableTop="@drawable/dashboard_button_selector"/>
            <Button android:id="@+id/action_six_button"
                style="@style/HomeButton"
                android:onClick="onActionSixClick"
                android:text="@string/dashboard_action"
                android:drawableTop="@drawable/dashboard_button_selector"/>
        </LinearLayout>
    </LinearLayout>
</LinearLayout>




Other helpful projects


In Android ecosystem there are many helpful projects with very easily compatible licenses for developers.

iosched - Google IO app by Google
This project contains a very complete example of an app conforming to Dashboard and Action bar UI design patterns. It is pretty big project though so I recommend using the android-ui-patterns project instead if you're looking for just Dashboard or Action bar.


GreenDroid library

List of project goals from the website:

  • Prevent loosing time at copying the same snippets of code over and over again.
  • Try to make Android applications alike. 
  • Help developers to code highly functional applications.
  • Leverage the power of the Android framework.
  • Use as much XML as possible.






If you know any other projects that could be helpful to other please leave a comment!