Lug 092011
 

In questa nuova puntata vediamo il primo esempio di interfaccia interattiva, in particolare ci soffermiamo nel disegnare un semplice pulsante sullo schermo a cui dovrà corrispondere una reazione da parte del nostro software. Per questa prima puntata passeremo inizialmente dalla via più semplice senza troppe complicazioni ma è bene sapere che non è l’unica via per ottenere lo scopo, è solo la più semplice ma anche la meno flessibile. In un secondo passaggio affrontiamo perciò un percorso più complesso ma che permette maggior flessibilità.

Oramai disegnare un pulsante sullo schermo è operazione di routine per chi ha seguito le passate lezioni, perciò dovremmo già essere in grado di farlo. Come da consuetudine, ad ogni nuova lezione vediamo qualche piccola modifica per cui eccovi il main.xml come l’ho usato nell’esempio che vi propongo quest’oggi:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:stretchColumns="*"> 
<Button 
android:layout_height="fill_parent" 
android:layout_width="fill_parent" 
android:text="testo pulsante" 
android:id="@+id/button1" 
android:onClick="miafunzione"/> 
</LinearLayout>

Questo layout prepara un grosso pulsante con la scritta “testo pulsante” che occupa quasi l’intero schermo del nostro dispositivo. Abbiamo utilizzato, e poi vedremo perchè, il campo android:id, come nella lezione sul relativelayout che se non avete letto potete trovare qui nel caso vogliate approfondire l’argomento. La novità rispetto a quanto visto sinora stà nel campo “android:onClick” che guarda caso ci permette di selezionare il nome della funzione da richiamare quando viene premuto (click) il pulsante. Per quanto riguarda il layout non ci sono altre novità. Ora dobbiamo passare al listato vero e proprio per cui dobbiamo andare a fare le dovute modifice all’Activity del nostro programma. Il listato completo per questo primo rudimentale esempio è quello qui sotto:

package com.test;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class testactivity extends Activity {
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
  }
  public void miafunzione(View v)
  {
   Button MyButton = (Button) findViewById(R.id.button1); //@+id/button1
   MyButton.setText("Ok funziona!");
  };
}

Vi faccio notare i due import aggiuntivi all’iizio che non erano presenti nelle precedenti lezioni:

import android.view.View;
import android.widget.Button;

L’altra modifica si trova dopo la setContentView, qui infatti troviamo la funzione “miafunzione” nella quale viene utilizzata la findViewById associata all’id del nostro pulsante (@+id/button1 ricordate?) e la funzione setText per modificare il testo del pulsante stesso quando viene premuto. Se ora testate l’applicazione vedrete che dopo la pressione del pulsante il testo si trasforma in “Ok funziona!

Credo che sinora non ci siano particolari problemi. Facciamo un piccolo passo in più, aggiungiamo un secondo pulsante. Il main.xml è il seguente:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="fill_parent" 
android:layout_height="fill_parent" 
android:orientation="vertical"> 
<Button 
android:onClick="miafunzione" 
android:id="@+id/button1" 
android:layout_height="wrap_content" 
android:text="pulsante1" 
android:layout_width="fill_parent"> 
</Button> 
<Button 
android:layout_height="wrap_content" 
android:layout_width="fill_parent" 
android:text="pulsante2" 
android:id="@+id/button2" 
android:onClick="miafunzione"> 
</Button> 
</LinearLayout>

Nulla di complesso. Ho aggiunto un secondo pulsante identificato come “pulsante 2″.Vi faccio notare che la funzione richiamata al momento del click è sempre la”miafunzione”, anche se potevamo creare una funzione diversa fatta ad ok.

Vediamo ora il listato vero e proprio:

package com.test;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class testactivity extends Activity {
 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.main);
 }
public void miafunzione(View v)
{
 if(v.getId()==R.id.button1)
 {
 Button MyButton = (Button) findViewById(R.id.button2);
 MyButton.setTextColor(0xff0000ff);
 }
 else if(v.getId()==R.id.button2)
 {
 Button MyButton = (Button) findViewById(R.id.button1);
 MyButton.setTextColor(0xffff0000);
 }
};
}

Come possiamo vedere, abbiamo modificato anche la “miafunzione” in modo da distinguere se è stato premuto il pulsante 1 o il 2.

android button

Esempio pulsanti android

Per farlo abbiamo sfruttato la view passata come argomento e la funzione getId che permette di discriminare quale elemento della view ha generato l’evento. Il resto è quasi identico a prima: in base al pulsante premuto se ne ricava l’istanza con findViewById() dopodichè ho utilizzato la funzione setTextColor per dare un output visibile sullo schermo. Si faccia attenzione che premendo il tasto 1 si cambia il colore della scritta del pulsante 2 e viceversa. Una volta premuti i due pulsanti la scritta del pulsante 1 sarà rossa, e quella del pulsante 2 sarà blu.

Vi faccio notare una cosa importante nella gestione dei colori. Infatti nella loro descrizione non ci sono i classici valori esadecimali delle tre componenti RGB (red green blu ossia rosso, verde e blu) ma c’è in aggiunta una prima componente che è il cosiddetto canale alfa che permette di indicare la “trasparenza” del colore. Con 0xff il colore sarà totalmente solido e con 0x00 sarà totalmente trasparente.

Ora riprendiamo il precedente esempio, ma anzichè seguire la strada più semplice passiamo per una via più tortuosa, cosa che ci permetterà di vedere con maggior dettaglio il reale meccanismo con cui vengono intercettati gli eventi.

Ecco qui sotto il main.xml dell’esempio che andiamo a vedere ora:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="fill_parent" 
android:layout_height="fill_parent" 
android:orientation="vertical"> 
<Button 
android:id="@+id/button1" 
android:layout_height="wrap_content" 
android:text="pulsante1" 
android:layout_width="fill_parent"> 
</Button> 
<Button 
android:id="@+id/button2" 
android:layout_height="wrap_content" 
android:text="pulsante2" 
android:layout_width="fill_parent"> 
</Button> 
</LinearLayout>

Come potete notare, l’unica ma fondamentale differenza è che non abbiamo specificato android:onClick=”miafunzione” nei due pulsanti per cui nel layout non viene descritto come saranno gestiti gli eventi. Per forza di cose se il layout non descrive come gestire gli venti, dovrà essere la nostra activity a doverlo fare, andiamo perciò a vedere il nostro listato:

package com.test;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.view.View.OnClickListener;

public class testactivity extends Activity {
    private Button MioPulsante1;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        OnClickListener mioClickListener = new OnClickListener()
        {
        @Override    
         public void onClick(View v)
         {
            if(v.getId()==R.id.button1)
            {
                Button MyButton = (Button) findViewById(R.id.button2); //@+id/button2
                MyButton.setTextColor(0xff0000ff);
            }
            else if(v.getId()==R.id.button2)
            {
                Button MyButton = (Button) findViewById(R.id.button1); //@+id/button1
                MyButton.setTextColor(0xffff0000);
            }
         }
        };    
        MioPulsante1 = (Button)this.findViewById(R.id.button1);
        MioPulsante1.setOnClickListener(mioClickListener);
        ((Button)this.findViewById(R.id.button2)).setOnClickListener(mioClickListener);
    }
}

Andiamo ad analizzare le differenze rispetto a prima. Vi faccio notare fra gli “import” la comparsa di “import android.view.View.OnClickListener;”. Android utilizza i cosidetti “event listeners” per catturare e gestire gli eveti. Ce ne sono di diversi tipi:

  • OnClickListener
  • OnLongClickListener
  • OnFocusChangeListener
  • OnKeyListener
  • OnTouchListener
  • OnCreateContextMenuListener

Credo sia piuttosto intuitivo capire che l’OnClickListener non è altro che l’event listener che risponde ai “click”, ossia alla pressione degli elementi grafici sullo schermo, indipendentemente che il click sia effettuato con un dispositivo touch piuttosto che con un mouse o altro. Il nostro scopo è perciò creare un event listener di tipo OnClickListener da collegare ai nostri pulsanti per intercettare i click e rispondere ad essi.

Con l’istruzione “OnClickListener mioClickListener = new OnClickListener() ” creiamo un’istanza ad un OnClickListener che utilizzeremo per gestire la pressione di entrambi i pulsanti. In alternativa è possibile creare due Listeners separati da associare ognuno ad un singolo pulsante, ma in questo esempio ne ho utilizzato uno solo che gestisce entrambi i pulsanti. All’interno vi è un override della funzione onClick che prende come parametro la view che ha generato l’evento. La funzione è del tutto sovrapponibile alla “miafunzione” vista nell’esempio iniziale e chiaramente viene richiamata al momento a cui viene effettuato il click sul pulsante.

Con le due righe di codice

        MioPulsante1 = (Button)this.findViewById(R.id.button1);
        MioPulsante1.setOnClickListener(mioClickListener);

andiamo a settare il listener sul singolo pulsante al fine di permettere la corretta risposta agli eventi. Faccio notare che, non a caso, all’inizio dell’activity c’era la dichiarazione “private Button MioPulsante1;” che ci permette di mantenere in memoria il “pulsante1” anche per eventuali successive modifiche. In ultimo viene settato anche il listener del secondo pulsante evitando di mantenere in memoria l’istanza allo stesso motivo per cui, giusto per variare un po’, si è usata la linea di codice ((Button)this.findViewById(R.id.button2)).setOnClickListener(mioClickListener);

Spero che anche questa nuova lezione sia apprezzata come le precedenti. Finalmente abbiamo interagito con gli elementi dello schermo anche se in maniera molto rudimentale uscendo finalmente dalla fasefatta di sola teoria ed interfaccia statica. Se avete commenti scrivete pure, risponderò al più presto.