Panoramica degli eventi di input

Prova il metodo Scrivi
Jetpack Compose è il toolkit consigliato per la UI per Android. Scopri come utilizzare il tocco e l'input in Compose.

Su Android, esistono più modi per intercettare gli eventi dall'interazione di un utente con la tua applicazione. Quando vengono considerati gli eventi all'interno dell'interfaccia utente, l'approccio è acquisire gli eventi dall'oggetto View specifico con cui interagisce l'utente. La classe View fornisce i mezzi per farlo.

All'interno delle varie classi View che utilizzerai per comporre il layout, potresti notare diversi metodi di callback pubblici che sembrano utili per gli eventi dell'interfaccia utente. Questi metodi vengono richiamati dal framework Android quando la rispettiva azione si verifica sull'oggetto. Ad esempio, quando si tocca una vista (come un pulsante), viene richiamato il metodo onTouchEvent() per quell'oggetto. Tuttavia, per intercettare questo errore, devi estendere la classe e sostituire il metodo. Tuttavia, estendere ogni oggetto View per gestire un evento di questo tipo non sarebbe una soluzione pratica. Ecco perché la classe View contiene anche una raccolta di interfacce nidificate con callback che puoi definire molto più facilmente. Queste interfacce, chiamate listener di eventi, sono la chiave per acquisire l'interazione dell'utente con la UI.

Anche se utilizzerai più comunemente i listener di eventi per ascoltare le interazioni degli utenti, potrebbe verificarsi un momento in cui vuoi estendere una classe View, per creare un componente personalizzato. Potresti voler estendere la classe Button per rendere qualcosa di più fantasioso. In questo caso, sarai in grado di definire i comportamenti predefiniti degli eventi per la tua classe utilizzando i gestori di eventi delle classi.

Listener di eventi

Un listener di eventi è un'interfaccia della classe View che contiene un singolo metodo di callback. Questi metodi verranno chiamati dal framework Android quando la visualizzazione in cui è stato registrato il listener viene attivata dall'interazione dell'utente con l'elemento nell'interfaccia utente.

Le interfacce del listener di eventi includono i seguenti metodi di callback:

onClick()
Da View.OnClickListener. Questo viene chiamato quando l'utente tocca l'elemento (in modalità touch) o si concentra sull'elemento con i tasti di navigazione o la trackball e preme il tasto "Invio" appropriato o preme sulla trackball.
onLongClick()
Da View.OnLongClickListener. Questo viene chiamato quando l'utente tocca e tiene premuto l'elemento (in modalità tocco) o si concentra sull'elemento con i tasti di navigazione o la trackball e tenendo premuto il tasto "Invio" appropriato oppure tenendo premuto sulla trackball (per un secondo).
onFocusChange()
Da View.OnFocusChangeListener. Questo viene chiamato quando l'utente si avvicina o si allontana dall'elemento utilizzando i tasti di navigazione o la trackball.
onKey()
Da View.OnKeyListener. Viene chiamato quando l'utente si concentra sull'elemento e preme o rilascia un tasto hardware sul dispositivo.
onTouch()
Da View.OnTouchListener. Questo viene chiamato quando l'utente esegue un'azione qualificata come evento tocco, inclusa una pressione, un rilascio o qualsiasi gesto di movimento sullo schermo (entro i limiti dell'elemento).
onCreateContextMenu()
Da View.OnCreateContextMenuListener. Questa operazione viene chiamata quando viene creato un menu contestuale (in seguito a un "clic lungo") prolungato. Consulta la discussione sui menu contestuali nella guida per gli sviluppatori Menu.

Questi metodi sono gli unici abitanti della rispettiva interfaccia. Per definire uno di questi metodi e gestire gli eventi, implementa l'interfaccia nidificata nell'attività o definiscila come classe anonima. Quindi, passa un'istanza dell'implementazione al rispettivo metodo View.set...Listener(). Ad esempio, richiama setOnClickListener() e passa la tua implementazione di OnClickListener.

L'esempio seguente mostra come registrare un listener al clic per un pulsante.

Kotlin

protected void onCreate(savedValues: Bundle) {
    ...
    val button: Button = findViewById(R.id.corky)
    // Register the onClick listener with the implementation above
    button.setOnClickListener { view ->
        // do something when the button is clicked
    }
    ...
}

Java

// Create an anonymous implementation of OnClickListener
private OnClickListener corkyListener = new OnClickListener() {
    public void onClick(View v) {
      // do something when the button is clicked
    }
};

protected void onCreate(Bundle savedValues) {
    ...
    // Capture our button from layout
    Button button = (Button)findViewById(R.id.corky);
    // Register the onClick listener with the implementation above
    button.setOnClickListener(corkyListener);
    ...
}

Potresti anche trovare più pratico implementare OnClickListener nella tua Attività. In questo modo eviterai il carico della classe e l'allocazione degli oggetti aggiuntivi. Ecco alcuni esempi:

Kotlin

class ExampleActivity : Activity(), OnClickListener {
  
    protected fun onCreate(savedValues: Bundle) {
        val button: Button = findViewById(R.id.corky)
        button.setOnClickListener(this)
    }

    // Implement the OnClickListener callback
    fun onClick(v: View) {
        // do something when the button is clicked
    }
}

Java

public class ExampleActivity extends Activity implements OnClickListener {
    protected void onCreate(Bundle savedValues) {
        ...
        Button button = (Button)findViewById(R.id.corky);
        button.setOnClickListener(this);
    }

    // Implement the OnClickListener callback
    public void onClick(View v) {
      // do something when the button is clicked
    }
    ...
}

Tieni presente che il callback onClick() nell'esempio precedente non ha un valore restituito, ma alcuni altri metodi listener di eventi devono restituire un valore booleano. Il motivo dipende dall'evento. Per i pochi che li supportano, ecco perché:

  • onLongClick(): restituisce un valore booleano che indica se hai usufruito dell'evento e non deve essere ulteriormente trasmesso. In altre parole, restituisce true per indicare che hai gestito l'evento e che dovrebbe interrompersi qui; restituisce false se non lo hai gestito e/o l'evento deve continuare in qualsiasi altro listener al clic.
  • onKey(): restituisce un valore booleano che indica se hai usufruito dell'evento e non deve essere ulteriormente trasmesso. In altre parole, restituisce true per indicare che hai gestito l'evento e che dovrebbe interrompersi qui; restituisce false se non lo hai gestito e/o l'evento deve continuare in qualsiasi altro listener on-key.
  • onTouch(): restituisce un valore booleano per indicare se il listener utilizza questo evento. La cosa importante è che questo evento può avere più azioni che si susseguono. Pertanto, se restituisci false quando viene ricevuto l'evento di azione down, indichi che non hai usufruito dell'evento e non ti interessa neanche le azioni successive di questo evento. Di conseguenza, non verranno richieste altre azioni nell'ambito dell'evento, come il gesto del dito o l'eventuale evento di azione verso l'alto.

Ricorda che gli eventi chiave hardware vengono sempre inviati alla vista attualmente in primo piano. Vengono inviate partendo dalla parte superiore della gerarchia di visualizzazione e poi verso il basso, fino a raggiungere la destinazione appropriata. Se la vista (o un elemento secondario della vista) è attualmente attiva, puoi vedere lo spostamento dell'evento utilizzando il metodo dispatchKeyEvent(). In alternativa all'acquisizione degli eventi chiave tramite la vista, puoi anche ricevere tutti gli eventi all'interno della tua attività con onKeyDown() e onKeyUp().

Inoltre, quando pensi all'input di testo per la tua applicazione, ricorda che molti dispositivi dispongono solo di metodi di input software. Questi metodi non devono essere basati su chiavi; alcuni potrebbero utilizzare input vocale, scrittura a mano libera e così via. Anche se un metodo di immissione presenta un'interfaccia simile a una tastiera, in genere non attiva la famiglia di eventi onKeyDown(). Non dovresti mai creare una UI che richieda il controllo di specifiche pressioni di tasti, a meno che tu non voglia limitare la tua applicazione ai dispositivi con una tastiera hardware. In particolare, non fare affidamento su questi metodi per convalidare l'input quando l'utente preme il tasto Invio; utilizza invece azioni come IME_ACTION_DONE per segnalare al metodo di input come la tua applicazione prevede di reagire, in modo che possa modificare la sua UI in modo significativo. Evita ipotesi su come dovrebbe funzionare un metodo di input software e affidati solo che fornisca testo già formattato alla tua applicazione.

Nota: Android chiama prima i gestori di eventi, poi i gestori predefiniti appropriati dalla definizione della classe. Di conseguenza, la restituzione di true da questi listener di eventi interromperà la propagazione dell'evento ad altri listener di eventi e bloccherà anche il callback al gestore di eventi predefinito nella vista. Assicurati quindi di voler terminare l'evento quando restituisci true.

Gestori di eventi

Se stai creando un componente personalizzato da View, puoi definire diversi metodi di callback utilizzati come gestori di eventi predefiniti. Nel documento sui componenti di visualizzazione personalizzata, scoprirai alcuni dei callback più comuni utilizzati per la gestione degli eventi, tra cui:

Esistono altri metodi che dovresti conoscere, che non fanno parte della classe View, ma possono influire direttamente sulla gestione degli eventi. Per la gestione di eventi più complessi all'interno di un layout, prendi in considerazione

Modalità touch

Quando un utente naviga in un'interfaccia utente con i tasti direzionali o una trackball, è necessario concentrare l'attenzione sugli elementi interattivi (come i pulsanti) in modo che l'utente possa vedere cosa accetta l'input. Tuttavia, se il dispositivo è dotato di funzionalità touch e l'utente inizia a interagire con l'interfaccia toccandola, non è più necessario evidenziare gli elementi o impostare lo stato attivo su una determinata Vista. Esiste quindi una modalità di interazione denominata "modalità touch".

Per un dispositivo con funzionalità touch, dopo che l'utente tocca lo schermo, viene attivata la modalità touch. Da questo momento in poi, saranno attivabili solo le viste per le quali isFocusableInTouchMode() è impostato su true, come i widget di modifica del testo. Le altre visualizzazioni toccabili, come i pulsanti, non vengono messe in evidenza quando vengono toccate; si limitano a attivare gli ascoltatori al clic quando vengono premuti.

Ogni volta che un utente preme un tasto direzionale o scorre con una trackball, il dispositivo uscirà dalla modalità touch e troverà una visualizzazione per mettere a fuoco. Ora l'utente può riprendere a interagire con l'interfaccia utente senza toccare lo schermo.

Lo stato della modalità touch viene mantenuto in tutto il sistema (tutte le finestre e le attività). Per eseguire una query sullo stato attuale, puoi chiamare isInTouchMode() per vedere se il dispositivo è attualmente in modalità touch.

Gestione dell'attenzione

Il framework gestirà il movimento di routine dello stato attivo in risposta all'input dell'utente. Ciò include la modifica dell'elemento attivo quando le viste vengono rimosse o nascoste o quando diventano disponibili nuove viste. Le visualizzazioni indicano la loro disponibilità a concentrarsi con il metodo isFocusable(). Per scegliere se una vista può rendere lo stato attivo, chiama setFocusable(). In modalità tocco, puoi chiedere se una vista consente lo stato attivo con isFocusableInTouchMode(). Puoi modificare questa impostazione con setFocusableInTouchMode().

Sui dispositivi con Android 9 (livello API 28) o versioni successive, le attività non assegnano un focus iniziale. Devi invece richiedere esplicitamente lo stato attivo iniziale, se vuoi.

Il movimento di messa a fuoco si basa su un algoritmo che trova il vicino più prossimo in una determinata direzione. In rari casi, l'algoritmo predefinito potrebbe non corrispondere al comportamento previsto dello sviluppatore. In queste situazioni, puoi fornire override espliciti con i seguenti attributi XML nel file di layout: nextFocusDown, nextFocusLeft, nextFocusRight e nextFocusUp. Aggiungi uno di questi attributi alla vista da cui l'elemento attivo abbandona lo stato attivo. Definisci il valore dell'attributo che deve essere l'ID della vista a cui impostare lo stato attivo. Ecco alcuni esempi:

<LinearLayout
    android:orientation="vertical"
    ... >
  <Button android:id="@+id/top"
          android:nextFocusUp="@+id/bottom"
          ... />
  <Button android:id="@+id/bottom"
          android:nextFocusDown="@+id/top"
          ... />
</LinearLayout>

In questo layout verticale, la navigazione verso l'alto dal primo pulsante non consente di spostarsi da un punto all'altro né verso il basso dal secondo pulsante. Ora che il pulsante in alto ha definito quello inferiore come nextFocusUp (e viceversa), lo stato attivo della navigazione passerà dall'alto verso il basso e dal basso verso l'alto.

Se vuoi dichiarare una vista come attivabile nella tua UI (quando tradizionalmente non è attiva), aggiungi l'attributo XML android:focusable alla vista, nella dichiarazione relativa al layout. Imposta il valore true. Puoi anche impostare una vista come attivabile in modalità touch con android:focusableInTouchMode.

Per richiedere che una determinata Vista diventi attiva, chiama requestFocus().

Per ascoltare gli eventi di stato attivo (ricevere una notifica quando una vista riceve o perde lo stato attivo), utilizza onFocusChange(), come spiegato nella sezione Listener di eventi.