lundi 24 octobre 2011

How To Build A Dashboard User Interface In Android



I have been looking into user interface designs and patterns for Android. This note describes what I have learned from building a demo app that illustrates theDashboard user interface pattern.
The demo app has a main screen with six buttons. Each button takes you to a different section of the app. Each section has a title bar at the top. The title bar tells you where you are and provides actions that are common to all. In this case, there are two action buttons that take you to an About screen and a Search screen. For everything but the main page, there is a link back to the home screen of the app.
My example app is derived from the Schedule app that Google came out with for the 2010 Google IO conference. That app has a lot of interesting features worth studying, but what I was interested in is what it takes to do a dashboard.
The Google IO Schedule app was fully functional. I pared it down to the essential elements related to a dashboard. None of the activities do anything more than display a line or two of text. That makes it a good starting point for building your own dashboard app.
The following screenshots give you a little bit better idea of what the app looks like. The About screen and Feature 1 screen are simple placeholders for whatever the real thing turns out to be in your application. The third figure below shows what the screen looks like as a user presses the “Feature 4″ button.
Full source code for my Dashboard Demo app is available in my Google Docs shared folder: Dashboard demo source zip file.
How It Works – Image Buttons
Basically what you have is a layout of image buttons. When a button is clicked, the handler starts another activity. The only way back to the home activity is via the Home button that appears in all of the secondary activities.
All the layout of views is done in resources files in folder res/layouts.  I am assuming you are familiar with basic layouts, defining views within them, and connecting them to an activity so I will not cover those things here. (For more on activities, refer to “My Introduction To Android Activities“.)
One of the things I learned doing this demo was how to set up image buttons so the user gets visual feedback as the buttons are touched, selected, or clicked. There are two kinds of image buttons used: (1) the buttons in the title bar area for About and Search; (2) the buttons in the main part of the layout that are used to move to one of the main sections of the app.
Here is how a title bar button works. If you look inside any of the layout files (activity_home.xml, activity_f1.xml, etc.), you will see a LinearLayout definition for the title bar.
<LinearLayout style="@style/TitleBar">
...
</LinearLayout>
Inside of that there is an image button definition for the About screen. It indicates what image is used as the button and indicates what method gets called when the button is clicked.
<ImageButton style="@style/TitleBarAction"
            android:contentDescription="@string/description_about"
            android:src="@drawable/title_about"
            android:onClick="onClickAbout" />
What I learned from the Schedule app is that the drawable does not have to be an image. They used another xml file to define what the drawable looked like in each of the different states it could be in: default, pressed, and selected.  The following xml is in res/drawable/title_about.xml.
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_focused="true"
          android:state_pressed="true"
          android:drawable="@drawable/title_about_alt"/>
    <item android:state_focused="false"
          android:state_pressed="true"
          android:drawable="@drawable/title_about_alt"/>
    <item android:state_focused="true"
          android:drawable="@drawable/title_about_alt"/>
    <item android:state_focused="false"
          android:state_pressed="false"
          android:drawable="@drawable/title_about_default"/>
</selector>
It looks a bit complicated at first but what it is saying is that there are two images to be used: default and alt. Use alt when the image button is in focus or selected. The two images I used are these:
The second is the one shown when the user presses the button. If you have worked with web applications, you will see this is very similar to the way you do images that show up as the user moves the mouse over an image that is a linked to more information.
Each of the buttons you see for the six different sections of the app are also image buttons. For those, I used three distinct images so that the “pressed” button looks different than the button when it has focus. The three images for Feature 5 (the stars) are shown below.
Here is the xml in home_activity for the Feature 5 button.
<Button android:id="@+id/home_btn_feature1"
            style="@style/HomeButton"
            android:onClick="onClickFeature"
            android:text="@string/title_feature5"
           android:drawableTop="@drawable/home_button5" />
It refers to home_button5 as a drawable. That drawable is defined in its own xml file: home_button5.xml.
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_focused="true"
          android:state_pressed="true"
          android:drawable="@drawable/stars_pressed"/>
    <item android:state_focused="false"
          android:state_pressed="true"
          android:drawable="@drawable/stars_pressed"/>
    <item android:state_focused="true"
          android:drawable="@drawable/stars_selected"/>
    <item android:state_focused="false"
          android:state_pressed="false"
          android:drawable="@drawable/stars_default"/>
</selector>
For more on how to use these state lists, see StateListDrawable.

How It Works: Styles

The other thing new for me was the use of style definitions. In both of the button xml definitions in the preceding section, there were references to styles.
style="@style/TitleBarAction"
and
    style="@style/HomeButton"
Styles are defined in xml files in the resource folders.  They serve the same purpose as css files in html files. They allow you to separate the design from the content.
In res/values/styles.xml, you will find the following definition.
<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>
A good description of styles is at android.developer.com: “Applying Styles and Themes“.

How It Works: Click Handlers

If you have already built a few simple apps, building a dashboard app is not too hard. Once you get comfortable with the xml for image buttons, state lists, and styles, all you have left is implementing the onClick handlers that start the appropriate Activity.
Each activity is defined in its own class file. One thing I did was define an abstract superclass (DashboardActivity) so I would have a place to collect code common to all the activities. That means there is only one place to edit the code that starts the activities that make up the app.
It defines methods for starting the different activities. For instance, for the Search activity, it defines
public void onClickSearch (View v)
{
    startActivity (new Intent(getApplicationContext(), SearchActivity.class));
}
Returning to home is a bit different because you are in a secondary activity at the time you click the Home button. 
public void onClickHome (View v)
{
    goHome (this);
}
public void goHome(Context context) 
{
    final Intent intent = new Intent(context, HomeActivity.class);
    intent.setFlags (Intent.FLAG_ACTIVITY_CLEAR_TOP);
    context.startActivity (intent);
}
According to the Android developer documentation on Intents, the extra Intent flags result in taking the user back to the home activity after first closing the activity that was active. That seems like reasonable behavior for a dashboard app, which requires that you return home before moving to another section of the app.


Dashboard User Interface Pattern

One design pattern for user intefaces in Android is the Dashboard. Interest in that pattern is pretty high, starting with the session on Android UI Design Patterns at Google IO 2010.
After seeing that video, I really wanted to try implementing the Dashboard pattern. I searched for the Twitter app that they said would be open source, but I could never find it. Fortunately, the source code for the Schedule App is available. Studying that is what got me here to this blog article.
I like the Dashboard pattern because it matches the way I like to think about applications: web, mobile, or whatever. For websites, the things I like are:
  • Simple. Clean.
  • Make it easy for people to understand what they can do.
  • Information is the interface
  • Use plain English
  • No training required
For websites, I appreciate ones that “Don’t Make Me Think“. For me, a Dashboard is essentially that, as long as I take the time to think about what the important sections are and make those available on the home screen.
For more information about dashboards and other patterns, read “A Closer Look At Android’s Evolving UI Patterns“.

Source Code

Source code is available from my Google Docs shared folder:

Excellent Tutoriel pour les Débutant dans Android



Un tutoriel android pour tous les débutant
vous pouvez le télécharger sur MediFire



samedi 15 octobre 2011

Faire une application calculatrice



Aujourd’hui nous allons faire notre première application qui ressemble vraiment à une application. On commence petit, c’est une simple calculatrice qui nous permettra de revoir le principe des évènements, et du positionnement des Buttons principalement.

Alors pour commencer créez un nouveau projet et appelez le comme vous voulez. Personnellement j’ai choisi une compatibilité avec la version 1.6 d’Android, mais je pense que le code que je vais vous donner fonctionne également à partir de la version 1.5. Avant de partir tête baissée dans le code, je vous montre ce qu’on souhaite réaliser :


Code XML

Commençons par l’interface graphique via le fichier main.xml, pour ce qui fera figure d’écran on va utiliser un EditText qui aura les propriétés suivantes :

<EditText android:id="@+id/EditText01"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:textSize="20px"
  android:editable="false"
  android:cursorVisible="false"
  />
On étend l’affichage de l’EditBox en largeur mais pas en hauteur, grâce à l’attribut editable on ne permet pas à l’utilisateur d’entrer directement du texte avec le clavier virtuel, et pour une question d’esthétisme on supprime le curseur à l’aide de l’attribut cursorVisible.

Passons maintenant à l’affichage des boutons. Nous allons voir comment faire pour une rangée et se sera la même chose pour toutes les autres rangées. Je vous donne tout de suite le code et je vous explique après les deux-trois choses à retenir.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="horizontal"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     >
 
     <Button android:id="@+id/button1"
      android:text="1"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   />
 
  <Button android:id="@+id/button2"
      android:text="2"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   />
 
  <Button android:id="@+id/button3"
      android:text="3"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   />
 
  <Button android:id="@+id/buttonPlus"
      android:text="+"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   />
 </LinearLayout>
L’astuce pour placer les boutons en ligne est de les placer dans un LinearLayout complété de l’attributorientation avec la valeur horizontal, et définir l’attribut layout_width des boutons fill_parent. Néanmoins si on laisse dans l’état on ne verra que le premier bouton de la rangée, il faut donc attribuer à chaque bouton un layout_weight de 1.

On applique cela pour chaque rangée de boutons ainsi que pour le bouton égal rien de plus simple, il suffit de définir l’attribut layout_width avec la valeur fill_parent. On obtient alors le fichier XML suivant :
<?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="fill_parent"
    >
 
 <EditText android:id="@+id/EditText01"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:textSize="20px"
  android:editable="false"
  android:cursorVisible="false"
  />
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="horizontal"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     >
 
     <Button android:id="@+id/button1"
      android:text="1"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   />
 
  <Button android:id="@+id/button2"
      android:text="2"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   />
 
  <Button android:id="@+id/button3"
      android:text="3"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   />
 
  <Button android:id="@+id/buttonPlus"
      android:text="+"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   />
 </LinearLayout>
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="horizontal"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     >
 
     <Button android:id="@+id/button4"
      android:text="4"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   />
 
  <Button android:id="@+id/button5"
      android:text="5"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   />
 
  <Button android:id="@+id/button6"
      android:text="6"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   />
 
  <Button android:id="@+id/buttonMoins"
      android:text="-"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   />
 
 </LinearLayout>
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="horizontal"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     >
 
     <Button android:id="@+id/button7"
      android:text="7"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   />
 
  <Button android:id="@+id/button8"
      android:text="8"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   />
 
  <Button android:id="@+id/button9"
      android:text="9"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   />
 
  <Button android:id="@+id/buttonMultiplier"
      android:text="*"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   />
 
 </LinearLayout>
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="horizontal"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     >
 
     <Button android:id="@+id/button0"
      android:text="0"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   />
 
  <Button android:id="@+id/buttonPoint"
      android:text="."
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   />
 
  <Button android:id="@+id/buttonC"
      android:text="C"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   />
 
  <Button android:id="@+id/buttonDivision"
      android:text="/"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   />
 
 </LinearLayout>
 
 <Button android:id="@+id/buttonEgal"
      android:text="="
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   />
 
 <ImageView android:id="@+id/logo"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:src="@drawable/logo_tuto_mobile"
   android:paddingTop="20px"
 />
</LinearLayout>

Code JAVA

Passons maintenant au code java. Pour programmer cette petite calculatrice, j’ai adapté un code trouvé sur le site du zero. Je vous donne tout de suite le code JAVA commenté :
package com.tutomobile.android.calculatrice;
 
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
 
public class Tutoriel4_Android extends Activity {
 
 //On déclare toutes les variables dont on aura besoin
 Button button0;
 Button button1;
 Button button2;
 Button button3;
 Button button4;
 Button button5;
 Button button6;
 Button button7;
 Button button8;
 Button button9;
 Button buttonPlus;
 Button buttonMoins;
 Button buttonDiv;
 Button buttonMul;
 Button buttonC;
 Button buttonEgal;
 Button buttonPoint;
 EditText ecran;
 
 private double chiffre1;
 private boolean clicOperateur = false;
 private boolean update = false;
 private String operateur = "";
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        //On récupère tout les éléments de notre interface graphique grâce aux ID
        button0 = (Button) findViewById(R.id.button0);
        button1 = (Button) findViewById(R.id.button1);
        button2 = (Button) findViewById(R.id.button2);
        button3 = (Button) findViewById(R.id.button3);
        button4 = (Button) findViewById(R.id.button4);
        button5 = (Button) findViewById(R.id.button5);
        button6 = (Button) findViewById(R.id.button6);
        button7 = (Button) findViewById(R.id.button7);
        button8 = (Button) findViewById(R.id.button8);
        button9 = (Button) findViewById(R.id.button9);
        buttonPoint = (Button) findViewById(R.id.buttonPoint);
        buttonPlus = (Button) findViewById(R.id.buttonPlus);
        buttonMoins = (Button) findViewById(R.id.buttonMoins);
        buttonDiv = (Button) findViewById(R.id.buttonDivision);
        buttonMul = (Button) findViewById(R.id.buttonMultiplier);
        buttonC = (Button) findViewById(R.id.buttonC);
        buttonEgal = (Button) findViewById(R.id.buttonEgal);
 
        ecran = (EditText) findViewById(R.id.EditText01);
 
        //On attribut un écouteur d'évènement à tout les boutons
        buttonPlus.setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
          plusClick();
         }
        });
 
        buttonMoins.setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
          moinsClick();
         }
        });
 
        buttonDiv.setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
          divClick();
         }
        });
 
        buttonMul.setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
          mulClick();
         }
        });
 
        buttonC.setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
          resetClick();
         }
        });
 
        buttonEgal.setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
          egalClick();
         }
        });
 
        buttonPoint.setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
          chiffreClick(".");
         }
        });
 
        button0.setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
          chiffreClick("0");
         }
        });
 
        button1.setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
          chiffreClick("1");
         }
        });
 
        button2.setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
          chiffreClick("2");
         }
        });
 
        button3.setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
          chiffreClick("3");
         }
        });
 
        button4.setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
          chiffreClick("4");
         }
        });
 
        button5.setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
          chiffreClick("5");
         }
        });
 
        button6.setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
          chiffreClick("6");
         }
        });
 
        button7.setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
          chiffreClick("7");
         }
        });
 
        button8.setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
          chiffreClick("8");
         }
        });
 
        button9.setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
          chiffreClick("9");
         }
        });
 
    }
 
    //voici la méthode qui est exécutée lorsque l'on clique sur un bouton chiffre
    public void chiffreClick(String str) {
        if(update){
                update = false;
        }else{
            if(!ecran.getText().equals("0"))
             str = ecran.getText() + str;
        }
        ecran.setText(str);
    }
 
    //voici la méthode qui est  exécutée lorsque l'on clique sur le bouton +
    public void plusClick(){
 
     if(clicOperateur){
      calcul();
            ecran.setText(String.valueOf(chiffre1));
        }else{
            chiffre1 = Double.valueOf(ecran.getText().toString()).doubleValue();
            clicOperateur = true;
        }
        operateur = "+";
        update = true;
    }
 
    //voici la méthode qui est  exécutée lorsque l'on clique sur le bouton -
    public void moinsClick(){
     if(clicOperateur){
      calcul();
            ecran.setText(String.valueOf(chiffre1));
        }else{
            chiffre1 = Double.valueOf(ecran.getText().toString()).doubleValue();
            clicOperateur = true;
        }
        operateur = "-";
        update = true;
    }
 
    //voici la méthode qui est  exécutée lorsque l'on clique sur le bouton *
    public void mulClick(){
     if(clicOperateur){
      calcul();
      ecran.setText(String.valueOf(chiffre1));
        }else{
            chiffre1 = Double.valueOf(ecran.getText().toString()).doubleValue();
            clicOperateur = true;
        }
        operateur = "*";
        update = true;
    }
 
    //voici la méthode qui est  exécutée lorsque l'on clique sur le bouton /
    public void divClick(){
      if(clicOperateur){
       calcul();
       ecran.setText(String.valueOf(chiffre1));
         }else{
          chiffre1 = Double.valueOf(ecran.getText().toString()).doubleValue();
          clicOperateur = true;
         }
         operateur = "/";
         update = true;
    }
 
    //voici la méthode qui est  exécutée lorsque l'on clique sur le bouton =
    public void egalClick(){
     calcul();
        update = true;
        clicOperateur = false;
    }
 
    //voici la méthode qui est  exécutée lorsque l'on clique sur le bouton C
    public void resetClick(){
      clicOperateur = false;
         update = true;
         chiffre1 = 0;
         operateur = "";
         ecran.setText("");
    }
 
    //Voici la méthode qui fait le calcul qui a été demandé par l'utilisateur
    private void calcul(){
        if(operateur.equals("+")){
         chiffre1 = chiffre1 + Double.valueOf(ecran.getText().toString()).doubleValue();
            ecran.setText(String.valueOf(chiffre1));
        }
 
        if(operateur.equals("-")){
         chiffre1 = chiffre1 - Double.valueOf(ecran.getText().toString()).doubleValue();
            ecran.setText(String.valueOf(chiffre1));
        }
 
        if(operateur.equals("*")){
                chiffre1 = chiffre1 * Double.valueOf(ecran.getText().toString()).doubleValue();
                ecran.setText(String.valueOf(chiffre1));
        }
 
        if(operateur.equals("/")){
         try{
             chiffre1 = chiffre1 / Double.valueOf(ecran.getText().toString()).doubleValue();
                ecran.setText(String.valueOf(chiffre1));
            }catch(ArithmeticException e){
                ecran.setText("0");
            }
        }
    }
}

Twitter Delicious Facebook Digg Stumbleupon Favorites More

 
Design by Free Android website | Bloggerized by wassim El mririe - Ramzi Essid | TO Best Web Host