Android : Implementación de un patrón de diseño Dashboard

[Fuente: http://www.javacodegeeks.com/2012/06/android-dashboard-design-pattern.html]

[audio http://wpcom.files.wordpress.com/2007/01/mattmullenweg-interview.mp3]

[youtube=http://www.youtube.com/watch?v=JaNH56Vpg-A&w=640&h=385]

[recently_posts]

En breve, diremos que un Dashboard es una página conteniendo símbolos claros y grandes para acceder a la funcionalidad principal y opcionalmente un área para información de noticias relevantes.

El principal objetivo de este artículo es implementar un patrón de diseño de Dashboard como el siguiente:

Paso 1: Crear el Title bar layout

Definiremos el layout de la title bar (header o cabecera) sólo una vez pero será requerida en varias pantallas. Mostraremos/ocultaremos el botón de Home y otros botones cuandoquiera que son necesitados. Una vez que has hecho el title bar layout, podemos utilizarlo el mismo layout en otros layouts utilizando ViewStub.

He aquí un ejemplo del  (header) xml layout:

header.xml

<?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="wrap_content"
	    android:background="@color/title_background" >

	    <LinearLayout
	        android:id="@+id/panelIconLeft"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:layout_alignParentLeft="true"
	        android:layout_centerVertical="true"
	        android:layout_margin="5dp" >

	        <Button
	            android:id="@+id/btnHome"
	            android:layout_width="wrap_content"
	            android:layout_height="wrap_content"
	            android:background="@drawable/ic_home"
	            android:onClick="btnHomeClick" />
	    </LinearLayout>

	    <TextView
	        android:id="@+id/txtHeading"
	        style="@style/heading_text"
	        android:layout_width="fill_parent"
	        android:layout_height="wrap_content"
	        android:layout_centerInParent="true"
	        android:layout_marginLeft="5dp"
	        android:layout_marginRight="5dp"
	        android:layout_toLeftOf="@+id/panelIconRight"
	        android:layout_toRightOf="@id/panelIconLeft"
	        android:ellipsize="marquee"
	        android:focusable="true"
	        android:focusableInTouchMode="true"
	        android:gravity="center"
	        android:marqueeRepeatLimit="marquee_forever"
	        android:singleLine="true"
	        android:text=""
	        android:textColor="@android:color/white" />

	    <LinearLayout
	        android:id="@+id/panelIconRight"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:layout_alignParentRight="true"
	        android:layout_centerVertical="true"
	        android:layout_margin="5dp" >

	        <Button
	            android:id="@+id/btnFeedback"
	            android:layout_width="wrap_content"
	            android:layout_height="wrap_content"
	            android:background="@drawable/ic_feedback"
	            android:onClick="btnFeedbackClick" />
	    </LinearLayout>

	</RelativeLayout>

El código de arriba hace referencias a estilos de styles.xml y dimensiones de dimen.xml:

styles.xml

<?xml version="1.0" encoding="utf-8"?>
	<resources>
	<style name="heading_text">
	        <item name="android:textColor">#ff000000</item>
	        <item name="android:textStyle">bold</item>
	        <item name="android:textSize">16sp</item>
	        <item name="android:padding">5dp</item>
	    </style>
	<style name="HomeButton">
	        <item name="android:layout_gravity">center_vertical</item>
	        <item name="android:layout_width">fill_parent</item>
	        <item name="android:layout_height">wrap_content</item>
	        <item name="android:layout_weight">1</item>
	        <item name="android:gravity">center_horizontal</item>
	        <item name="android:textSize">@dimen/text_size_medium</item>
	        <item name="android:textStyle">normal</item>
	        <item name="android:textColor">@color/foreground1</item>
	        <item name="android:background">@null</item>
	    </style>

	</resources>

dimen.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="title_height">45dip</dimen>
    <dimen name="text_size_small">14sp</dimen>
    <dimen name="text_size_medium">18sp</dimen>
    <dimen name="text_size_large">22sp</dimen>
</resources>

Paso 2: Crea una super (abstract) class

De hecho, en esta abstract super class, definiremos:

1) event handlers para los dos botones : Home and Feedback

2) Otros métodos

Los botones de Home y Feedback , que van a ser visibles en casi todas las activities y que requerirán las mismas acciones a ser realizadas (por ejemplo , llevar al usuario a la activity de Home). Así que en vez de escribir el mismo código en cada actividad, escribiremos un event handler sólo una vez en una clase abstracta que será superclase para todas las activities.

Puedes haberte dado cuenta en el fichero header.xml de donde están definidos los botones de Home y de Feedback:

android:onClick=”btnHomeClick” (Home button)

android:onClick=”btnFeedbackClick” (Feedback button)

, asi que definiremos este método una vez en la super clase (abstracta).

Por favor, buscate un ejemplo de ViewStub si nunca lo has utilizado.

Ahora , aquí está el código de la clase abstracta, la llamaremos DashboardActivity.java

package com.technotalkative.viewstubdemo;

	import android.app.Activity;
	import android.content.Intent;
	import android.os.Bundle;
	import android.view.View;
	import android.view.ViewStub;
	import android.widget.Button;
	import android.widget.TextView;

	public abstract class DashBoardActivity extends Activity {
	    /** Called when the activity is first created. */
	    @Override
	    public void onCreate(Bundle savedInstanceState) {
	        super.onCreate(savedInstanceState);
	    }

	    public void setHeader(String title, boolean btnHomeVisible, boolean btnFeedbackVisible)
	    {
	      ViewStub stub = (ViewStub) findViewById(R.id.vsHeader);
	      View inflated = stub.inflate();

	      TextView txtTitle = (TextView) inflated.findViewById(R.id.txtHeading);
	      txtTitle.setText(title);

	      Button btnHome = (Button) inflated.findViewById(R.id.btnHome);
	      if(!btnHomeVisible)
	       btnHome.setVisibility(View.INVISIBLE);

	      Button btnFeedback = (Button) inflated.findViewById(R.id.btnFeedback);
	      if(!btnFeedbackVisible)
	       btnFeedback.setVisibility(View.INVISIBLE);

	    }

	    /**
	     * Home button click handler
	     * @param v
	     */
	    public void btnHomeClick(View v)
	    {
	     Intent intent = new Intent(getApplicationContext(), HomeActivity.class);
	     intent.setFlags (Intent.FLAG_ACTIVITY_CLEAR_TOP);
	     startActivity(intent);

	    }

	    /**
	     * Feedback button click handler
	     * @param v
	     */
	    public void btnFeedbackClick(View v)
	    {
	     Intent intent = new Intent(getApplicationContext(), FeedbackActivity.class);
	     startActivity(intent);
	    }
	}

Step 3: Define Dashboard layout

01 <?xml version="1.0" encoding="utf-8"?>
02 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
03     android:layout_width="fill_parent"
04     android:layout_height="fill_parent"
05     android:orientation="vertical" >
06
07     
08  
09
10     <ViewStub
11         android:id="@+id/vsHeader"
12         android:layout_width="fill_parent"
13         android:layout_height="wrap_content"
14         android:inflatedId="@+id/header"
15         android:layout="@layout/header" />
16
17     <LinearLayout
18         android:layout_width="fill_parent"
19         android:layout_height="wrap_content"
20         android:layout_weight="1"
21         android:orientation="vertical"
22         android:padding="6dip" >
23
24         <LinearLayout
25             android:layout_width="fill_parent"
26             android:layout_height="wrap_content"
27             android:layout_weight="1"
28             android:orientation="horizontal" >
29
30             <Button
31                 android:id="@+id/main_btn_eclair"
32                 style="@style/HomeButton"
33                 android:drawableTop="@drawable/android_eclair_logo"
34                 android:onClick="onButtonClicker"
35                 android:text="@string/EclairActivityTitle" />
36
37             <Button
38                 android:id="@+id/main_btn_froyo"
39                 style="@style/HomeButton"
40                 android:drawableTop="@drawable/android__logo_froyo"
41                 android:onClick="onButtonClicker"
42                 android:text="@string/FroyoActivityTitle" />
43         </LinearLayout>
44
45         <LinearLayout
46             android:layout_width="fill_parent"
47             android:layout_height="wrap_content"
48             android:layout_weight="1"
49             android:orientation="horizontal" >
50
51             <Button
52                 android:id="@+id/main_btn_gingerbread"
53                 style="@style/HomeButton"
54                 android:drawableTop="@drawable/android_gingerbread_logo"
55                 android:onClick="onButtonClicker"
56                 android:text="@string/GingerbreadActivityTitle" />
57
58             <Button
59                 android:id="@+id/main_btn_honeycomb"
60                 style="@style/HomeButton"
61                 android:drawableTop="@drawable/android_honeycomb_logo"
62                 android:onClick="onButtonClicker"
63                 android:text="@string/HoneycombActivityTitle" />
64         </LinearLayout>
65
66         <LinearLayout
67             android:layout_width="fill_parent"
68             android:layout_height="wrap_content"
69             android:layout_weight="1"
70             android:orientation="horizontal" >
71
72             <Button
73                 android:id="@+id/main_btn_ics"
74                 style="@style/HomeButton"
75                 android:drawableTop="@drawable/android_ics_logo"
76                 android:onClick="onButtonClicker"
77                 android:text="@string/ICSActivityTitle" />
78
79             <Button
80                 android:id="@+id/main_btn_jellybean"
81                 style="@style/HomeButton"
82                 android:drawableTop="@drawable/android_jellybean_logo"
83                 android:onClick="onButtonClicker"
84                 android:text="@string/JellyBeanActivityTitle" />
85         </LinearLayout>
86     </LinearLayout>
87 </LinearLayout>

Step 4: Define activity for handling this dashboard layout buttons click events.

In this activity, you will find the usage of setHeader() method to set the header for home activity, yes in this method i have passed “false” for home button because its already a home activity, but i have passed “true” for feedback button because feedback is needed to be visible. Other process are same as defining button click handlers.

01 package com.technotalkative.viewstubdemo;
02
03 import android.content.Intent;
04 import android.os.Bundle;
05 import android.view.View;
06
07 public class HomeActivity extends DashBoardActivity {
08     /** Called when the activity is first created. */
09     @Override
10     public void onCreate(Bundle savedInstanceState) {
11         super.onCreate(savedInstanceState);
12         setContentView(R.layout.main);
13         setHeader(getString(R.string.HomeActivityTitle), falsetrue);
14     }
15
16     /**
17      * Button click handler on Main activity
18      * @param v
19      */
20     public void onButtonClicker(View v)
21     {
22      Intent intent;
23
24      switch (v.getId()) {
25   case R.id.main_btn_eclair:
26    intent = new Intent(this, Activity_Eclair.class);
27    startActivity(intent);
28    break;
29
30   case R.id.main_btn_froyo:
31    intent = new Intent(this, Activity_Froyo.class);
32    startActivity(intent);
33    break;
34
35   case R.id.main_btn_gingerbread:
36    intent = new Intent(this, Activity_Gingerbread.class);
37    startActivity(intent);
38    break;
39
40   case R.id.main_btn_honeycomb:
41    intent = new Intent(this, Activity_Honeycomb.class);
42    startActivity(intent);
43    break;
44
45   case R.id.main_btn_ics:
46    intent = new Intent(this, Activity_ICS.class);
47    startActivity(intent);
48    break;
49
50   case R.id.main_btn_jellybean:
51    intent = new Intent(this, Activity_JellyBean.class);
52    startActivity(intent);
53    break;
54   default:
55    break;
56   }
57     }
58 }

Step 5: Define other activities and their UI layouts

Now, its time to define activities that we want to display based on the particular button click from dashboard. So define every activities and their layouts. Don’t forget to call setHeader() method wherever necessary.

Here is one example for such activity – Activity_Eclair.java

01 package com.technotalkative.viewstubdemo;
02
03 import android.os.Bundle;
04
05 public class Activity_Eclair extends DashBoardActivity {
06     /** Called when the activity is first created. */
07     @Override
08     public void onCreate(Bundle savedInstanceState) {
09         super.onCreate(savedInstanceState);
10         setContentView(R.layout.activity_eclair);
11         setHeader(getString(R.string.EclairActivityTitle), truetrue);
12     }
13 }

activity_eclair.xml

01 <?xml version="1.0" encoding="utf-8"?>
02 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
03     android:layout_width="fill_parent"
04     android:layout_height="fill_parent"
05     android:orientation="vertical" >
06
07     
08  
09
10     <ViewStub
11         android:id="@+id/vsHeader"
12         android:layout_width="fill_parent"
13         android:layout_height="wrap_content"
14         android:inflatedId="@+id/header"
15         android:layout="@layout/header" />
16
17     <TextView
18         android:id="@+id/textView1"
19         android:layout_width="match_parent"
20         android:layout_height="match_parent"
21         android:gravity="center"
22         android:text="@string/EclairActivityTitle" />
23
24 </LinearLayout>

Step 6: Declare activities inside the AnroidManifest.xml file

Now you are DONE :)

Output:

Home screen _ Landscape
inner screen
inner screen

You can download source code from here: Android – Dashboard pattern implementation

Feedback/review are always welcome :)

Reference: Android – Dashboard design pattern implementation from our JCG partner Paresh N. Mayani at the TechnoTalkative blog.