Abbiamo imparato finora a gestire il touch. Il display percepisce il modo in cui puntatori – in genere le dita dell'utente – ne toccano la superficie
prendendo nota delle coordinate, dei movimenti e di tutte le variazioni relative.
L'insieme delle variazioni impresse dai puntatori viene intesa nel suo complesso come una gestualità, o gesture come più comunemente si usa dire.
In effetti, i touch e le relative modifiche potrebbero essere analizzate, come visto, con oggetti MotionEvent all'interno del metodo di callback
OnTouchEvent. Ma la frequenza con cui appaiono nel mondo mobile gestures comuni ha indotto sin da subito il team di Android a prevedere appositi metodi per
la loro gestione.
Esiste nelle API Android una classe fondamentale per la gestione delle gestures, GestureDetector. Il suo costruttore prende in input due
parametri, il Context ed un listener che implementa OnGestureListener:
public class MainActivity extends Activity implements OnGestureListener
{
private GestureDetector detector;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
detector=new GestureDetector(this, this);
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
detector.onTouchEvent(event);
return true;
}
. . .
. . .
}
Lo stralcio di codice appena illustrato mostra come può essere impostata un'Activity in cui vengano trattate le gesture. In dettaglio, si è:
- implementata l'interfaccia OnGestureListener nell'Activity;
- impostato un GestureDetector come membro privato;
- inizializzato il detector all'interno dell'onCreate passando due riferimenti all'Activity stessa: il primo in quanto Context, il secondo come listener
per le gestures; - fatto override del metodo onTouchEvent dell'Activity che "gira" il MotionEvent ricevuto al detector. Questo passaggio è fondamentale: stabilisce
l'aggancio tra la ricezione dei touch e la loro interpretazione in quanto gestures.
L'implementazione di OnGestureListener richiede l'override di diversi metodi che rappresentano le principali gestures:
- onDown: rappresenta l'atto di posare il dito sul display. È praticamente l'inizio di qualunque gesture;
- onLongPress: viene invocato solo quando la pressione sul display rimane prolungata;
- onFling: è ciò che comunemente viene chiamato swipe, l'atto del dito con cui si mima lo sfogliare delle pagine verso destra o sinistra;
- onScroll: richiama il concetto comune di fare scorrere una lista di elementi verticalmente o orizzontalmente. Come gesture, viene associato in senso più
ampio a qualsiasi sfregamento del dito sul display senza distacco; - onShowPress: dovuto alla pressione del dito sul display nello stesso punto che non è ancora stata interrotta quindi al momento non interpretabile in
altra maniera; - onSingleTapUp: il classico tap, un colpetto singolo su display assimilabile ad un click.
Come si può prevedere, un'unica gesture può richiamare più metodi tra quelli citati. Ad esempio, pensiamo al fling, la sequenza di metodi che viene
invocata è:
- onDown al momento di posare il dito sul display;
- onScroll – non uno solo ma una serie – durante lo sfregamento del dito sul display;
- onFling, al finale, solo quando il dito viene distaccato dal display.
Solo l'ultimo punto rappresenta il completamento della gesture con la sua definitiva connotazione.
Visto che ne abbiamo fatto cenno vediamo un piccolo esempio che può essere attuato all'interno del metodo onFling:
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
{
if (e1.getX()>e2.getX())
Toast.makeText(getApplicationContext(), "verso sx", Toast.LENGTH_SHORT).show();
else
Toast.makeText(getApplicationContext(), "verso dx", Toast.LENGTH_SHORT).show();
return true;
}
questa implementazione mostra che vengono ricevuti due oggetti MotionEvent, uno rappresenta il punto di inizio della gesture (il momento di down in cui il
dito è stato posato sul display) e l'altro che rappresenta il punto in cui il dito viene sollevato completando il fling.
La differenza tra le ascisse dei due oggetti MotionEvent permette di scoprire se lo swipe è stato eseguito verso destra o sinistra, risultato che viene
notificato mediante Toast.