IMPORTANT: Per accedir als fitxer de subversion: http://acacha.org/svn (sense password). Poc a poc s'aniran migrant els enllaços. Encara però funciona el subversion de la farga però no se sap fins quan... (usuari: prova i la paraula de pas 123456)

Introducció

ELs dashboard d'Android és un element important dins de les aplicacions Android, ja que proporciona una navegació fàcil dins de totes les funcionalitats que ofereix una aplició.

Dispositius i Pantalles

Android dona suport a milions de dispositius

Tutorial

Realitzarem el tutorial que trobem dins de la següent pàgina, per a crear un dashboard d'una aplicació.

http://www.androidhive.info/2011/12/android-dashboard-design-tutorial/

Rescriurem el fitxer styles.xml que podrem trobar dins de la carpeta /res/values.

<resources>
    <style name="ActionBarCompat">
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">50dp</item>
        <item name="android:orientation">horizontal</item>
        <item name="android:background">@drawable/actionbar_background</item>
    </style>
       
    <style name="DashboardButton">
        <item name="android:layout_gravity">center_vertical</item>
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:gravity">center_horizontal</item>
        <item name="android:drawablePadding">2dp</item>
        <item name="android:textSize">16dp</item>
        <item name="android:textStyle">bold</item>
        <item name="android:textColor">#FFFFFF</item>
        <item name="android:background">@null</item>
    </style>    
    
   <style name="FooterBar">
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">40dp</item>
        <item name="android:orientation">horizontal</item>
        <item name="android:background">#dedede</item>
    </style>     
</resources>

Crearem dos imatges una per al fons del action bar i logo.

Afegirem un nou fitxer xml dins de /res/layout de nom actionbar_layout i el dixarem amb el contingut següent.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    style="@style/ActionBarCompat" >

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:clickable="false"
        android:paddingLeft="15dip"
        android:scaleType="center"
        android:src="@drawable/facebook_logo" />

</LinearLayout>

Seleccionarem les diferents icones que volem utilitzar amb la nostra aplicació podem utilitzar les nostres propies creant-les amb qualsevol programa d'edició fotogràfica com pot ser el photoshop o el gimp.

Crearem una nova classe de java de amb el següent nom DashboardLayout.java i contingut

public class DashboardLayout extends ViewGroup {

    private static final int UNEVEN_GRID_PENALTY_MULTIPLIER = 10;

    private int mMaxChildWidth = 0;
    private int mMaxChildHeight = 0;

    public DashboardLayout(Context context) {
        super(context, null);
    }

    public DashboardLayout(Context context, AttributeSet attrs) {
        super(context, attrs, 0);
    }

    public DashboardLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mMaxChildWidth = 0;
        mMaxChildHeight = 0;

        // Measure once to find the maximum child size.

        int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
                MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST);
        int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
                MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST);

        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() == GONE) {
                continue;
            }

            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);

            mMaxChildWidth = Math.max(mMaxChildWidth, child.getMeasuredWidth());
            mMaxChildHeight = Math.max(mMaxChildHeight, child.getMeasuredHeight());
        }

        // Measure again for each child to be exactly the same size.

        childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
                mMaxChildWidth, MeasureSpec.EXACTLY);
        childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
                mMaxChildHeight, MeasureSpec.EXACTLY);

        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() == GONE) {
                continue;
            }

            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        }

        setMeasuredDimension(
                resolveSize(mMaxChildWidth, widthMeasureSpec),
                resolveSize(mMaxChildHeight, heightMeasureSpec));
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int width = r - l;
        int height = b - t;

        final int count = getChildCount();

        // Calculate the number of visible children.
        int visibleCount = 0;
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() == GONE) {
                continue;
            }
            ++visibleCount;
        }

        if (visibleCount == 0) {
            return;
        }

        // Calculate what number of rows and columns will optimize for even horizontal and
        // vertical whitespace between items. Start with a 1 x N grid, then try 2 x N, and so on.
        int bestSpaceDifference = Integer.MAX_VALUE;
        int spaceDifference;

        // Horizontal and vertical space between items
        int hSpace = 0;
        int vSpace = 0;

        int cols = 1;
        int rows;

        while (true) {
            rows = (visibleCount - 1) / cols + 1;

            hSpace = ((width - mMaxChildWidth * cols) / (cols + 1));
            vSpace = ((height - mMaxChildHeight * rows) / (rows + 1));

            spaceDifference = Math.abs(vSpace - hSpace);
            if (rows * cols != visibleCount) {
                spaceDifference *= UNEVEN_GRID_PENALTY_MULTIPLIER;
            }

            if (spaceDifference < bestSpaceDifference) {
                // Found a better whitespace squareness/ratio
                bestSpaceDifference = spaceDifference;

                // If we found a better whitespace squareness and there's only 1 row, this is
                // the best we can do.
                if (rows == 1) {
                    break;
                }
            } else {
                // This is a worse whitespace ratio, use the previous value of cols and exit.
                --cols;
                rows = (visibleCount - 1) / cols + 1;
                hSpace = ((width - mMaxChildWidth * cols) / (cols + 1));
                vSpace = ((height - mMaxChildHeight * rows) / (rows + 1));
                break;
            }

            ++cols;
        }

        // Lay out children based on calculated best-fit number of rows and cols.

        // If we chose a layout that has negative horizontal or vertical space, force it to zero.
        hSpace = Math.max(0, hSpace);
        vSpace = Math.max(0, vSpace);

        // Re-use width/height variables to be child width/height.
        width = (width - hSpace * (cols + 1)) / cols;
        height = (height - vSpace * (rows + 1)) / rows;

        int left, top;
        int col, row;
        int visibleIndex = 0;
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() == GONE) {
                continue;
            }

            row = visibleIndex / cols;
            col = visibleIndex % cols;

            left = hSpace * (col + 1) + width * col;
            top = vSpace * (row + 1) + height * row;

            child.layout(left, top,
                    (hSpace == 0 && col == cols - 1) ? r : (left + width),
                    (vSpace == 0 && row == rows - 1) ? b : (top + height));
            ++visibleIndex;
        }
    }
}

Ara crearem el fitxer que contindrà el layout del dashboard com en els anteriors layouts o crearem dins de la carpeta /res/layout el nom que li donarem al fitxer serà fragment_layout.xml.

<com.androidhive.dashboard.DashboardLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_weight="1"
    android:background="#008080" >
	<!--  News Feed Button -->
    <Button
        android:id="@+id/btn_news_feed"
        style="@style/DashboardButton"
        android:drawableTop="@drawable/btn_newsfeed"
        android:text="News Feed" />
    
	<!--  Friends Button -->
    <Button
        android:id="@+id/btn_friends"
        style="@style/DashboardButton"
        android:drawableTop="@drawable/ic_action_add_person"
        android:text="Friends" />
    
	<!--  Messages Button -->
    <Button
        android:id="@+id/btn_messages"
        style="@style/DashboardButton"
        android:drawableTop="@drawable/ic_messages_default"
        android:text="Messages" />
	
    <!--  Places Button -->
    <Button
        android:id="@+id/btn_places"
        style="@style/DashboardButton"
        android:drawableTop="@drawable/btn_places"
        android:text="Places" />

    <!--  Events Button -->
    <Button
        android:id="@+id/btn_events"
        style="@style/DashboardButton"
        android:drawableTop="@drawable/ic_hardware_phone"
        android:text="Events" />

    <!--  Photos Button -->
    <Button
        android:id="@+id/btn_photos"
        style="@style/DashboardButton"
        android:drawableTop="@drawable/btn_photos"
        android:text="Photos" />

</com.androidhive.dashboard.DashboardLayout>

Ara crearem un nou fitxer que contindrà el peu de l'aplicació. Li donarem el nom de footer_layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    style="@style/FooterBar" >
	<TextView android:text="www.facebook.com"
	    	android:layout_width="fill_parent"
	    	android:layout_height="wrap_content"
	    	android:textColor="#606060"
	    	android:gravity="center"
	    	android:paddingTop="10dip"/>
</LinearLayout>

Fins ara hem dissenyat la Action Bar, Dashboard i peu de pàgina. Finalment hem de combinar tots els dissenys en un arxiu xml. dashboard_layout.xml.

<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">
    	<!-- Include Action Bar -->
    	<include layout="@layout/actionbar_layout"/>
    	
    	<!--  Include Fragmented dashboard -->	
		<include layout="@layout/fragment_layout"/>	
		
		<!--  Include Footer -->
		<include layout="@layout/footer_layout"/>
    	    
</LinearLayout>

Fins ara, hem creat un panell estàtic que no té funcionalitat total. Així que hem d'afegir algunes funcions com el llançament de les activitats independents per a cada icona en el dashboard. En aquest cas les 6 icones del panell de control, així que necessitem 6 Activitats un per a cada icona.

Obrim el fitxer de classe activitat principal i copiem el codi següent. ( AndroidDashboardDesignActivity.java)

public class AndroidDashboardDesignActivity extends Activity {
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.dashboard_layout);
        
        /**
         * Creating all buttons instances
         * */
        // Dashboard News feed button
        Button btn_newsfeed = (Button) findViewById(R.id.btn_news_feed);
        
        // Dashboard Friends button
        Button btn_friends = (Button) findViewById(R.id.btn_friends);
        
        // Dashboard Messages button
        Button btn_messages = (Button) findViewById(R.id.btn_messages);
        
        // Dashboard Places button
        Button btn_places = (Button) findViewById(R.id.btn_places);
        
        // Dashboard Events button
        Button btn_events = (Button) findViewById(R.id.btn_events);
        
        // Dashboard Photos button
        Button btn_photos = (Button) findViewById(R.id.btn_photos);
        
        /**
         * Handling all button click events
         * */
        
        // Listening to News Feed button click
        btn_newsfeed.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View view) {
				// Launching News Feed Screen
				Intent i = new Intent(getApplicationContext(), NewsFeedActivity.class);
				startActivity(i);
			}
		});
        
       // Listening Friends button click
        btn_friends.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View view) {
				// Launching News Feed Screen
				Intent i = new Intent(getApplicationContext(), FriendsActivity.class);
				startActivity(i);
			}
		});
        
        // Listening Messages button click
        btn_messages.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View view) {
				// Launching News Feed Screen
				Intent i = new Intent(getApplicationContext(), MessagesActivity.class);
				startActivity(i);
			}
		});
        
        // Listening to Places button click
        btn_places.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View view) {
				// Launching News Feed Screen
				Intent i = new Intent(getApplicationContext(), PlacesActivity.class);
				startActivity(i);
			}
		});
        
        // Listening to Events button click
        btn_events.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View view) {
				// Launching News Feed Screen
				Intent i = new Intent(getApplicationContext(), EventsActivity.class);
				startActivity(i);
			}
		});
        
        // Listening to Photos button click
        btn_photos.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View view) {
				// Launching News Feed Screen
				Intent i = new Intent(getApplicationContext(), PhotosActivity.class);
				startActivity(i);
			}
		});
    }
}

Crearem una nova activitat que ens farà que sigui funcional el botó news feed el nom de la classe serà NewsfeedsActivty.java

public class NewsFeedActivity extends Activity {
	 /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.news_feed_layout);
    }
}

Farem el mateix per a totes les activitats que tenim associades a cada un dels nostres botons.

Per a cada una de les activitats també crearem el seu diferent layout una mostra del que haurem de realitzar serà crear el layout associat a la nostra activitat NewsfeedsActivty el fitxer associat serà news_feed_layout.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#f8f9fe"
    android:orientation="vertical" >

    <include layout="@layout/actionbar_layout" />

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >

        <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:padding="15dip"
            android:text="News Feed Screen"
            android:textColor="#ff29549f"
            android:textSize="25dip"
            android:textStyle="bold" />
    </LinearLayout>

</LinearLayout>

No ens podem oblidar tampoc si volem que la nostra aplicació funcioni de modificar el fitxer de Manifest afegint-li les diferents activitats.

 <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:label="@string/app_name"
            android:name="com.androidhive.dashboard.AndroidDashboardDesignActivity" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- News Feed Activity -->
        <activity android:name="com.androidhive.dashboard.NewsFeedActivity" ></activity>

        <!-- Friends Activity -->
        <activity android:name="com.androidhive.dashboard.FriendsActivity" ></activity>

        <!-- Messages Activity -->
        <activity android:name="com.androidhive.dashboard.MessagesActivity" ></activity>

        <!-- Places Activity -->
        <activity android:name="com.androidhive.dashboard.PlacesActivity" ></activity>

        <!-- Events Activity -->
        <activity android:name="com.androidhive.dashboard.EventsActivity" ></activity>
        
        <!-- Photos Activity -->
        <activity android:name="com.androidhive.dashboard.PhotosActivity" ></activity>
    </application>

Podeu trobar el projecte a la següent direcció. https://github.com/jordiromero/androiddashboard

Enllaços Externs

Tutorial DashBoard

http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html