Panoramica degli eventi di input

Prova la modalità Scrivi
Jetpack Compose è il toolkit dell'interfaccia utente consigliato per Android. Scopri come usare tocco e input in Scrivi.

Su Android sono disponibili più modi per intercettare gli eventi provenienti dall'interazione di un utente con la tua applicazione. Nel considerare gli eventi all'interno dell'interfaccia utente, l'approccio consiste nell'acquisire gli eventi dallo specifico oggetto View con cui l'utente interagisce. La classe View fornisce i mezzi per farlo.

All'interno delle varie classi di viste che utilizzerai per scrivere il layout, potresti notare diversi metodi di callback pubblici che sembrano utili per gli eventi dell'interfaccia utente. Questi metodi vengono chiamati dal framework Android quando si verifica la rispettiva azione sull'oggetto. Ad esempio, quando si tocca una vista (come un pulsante), viene richiamato il metodo onTouchEvent() su quell'oggetto. Tuttavia, per intercettare l'errore, devi estendere la classe e sostituire il metodo. L'estensione di ogni oggetto View per gestire un evento di questo tipo non sarebbe però praticabile. Questo è il motivo per cui la classe View contiene anche una raccolta di interfacce nidificate con callback che puoi definire in modo molto più semplice. Queste interfacce, chiamate ascoltatori di eventi, sono la chiave per acquisire l'interazione dell'utente con la tua UI.

Sebbene utilizzerai più comunemente i listener di eventi per ascoltare le interazioni degli utenti, potrebbe capitare che tu voglia estendere una classe View per creare un componente personalizzato. Potresti voler estendere la classe Button per creare qualcosa di più elaborato. In questo caso, potrai definire i comportamenti predefiniti degli eventi per la tua classe utilizzando la classe gestori di eventi.

Listener di eventi

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

Nelle interfacce del listener di eventi sono inclusi i seguenti metodi di callback:

onClick()
A partire da View.OnClickListener. Viene richiamata quando l'utente tocca l'elemento (in modalità tocco) o si concentra sull'elemento con i tasti di navigazione o la trackball e preme il tasto "Invio" appropriato o preme sulla trackball.
onLongClick()
A partire da View.OnLongClickListener. Viene richiamata quando l'utente tocca e tiene premuto l'elemento (in modalità tocco) oppure si concentra sull'elemento con i tasti di navigazione o la trackball e tiene premuto il tasto "Invio" appropriato o tiene premuto sulla trackball (per un secondo).
onFocusChange()
A partire da View.OnFocusChangeListener. Viene richiamata quando l'utente entra o esce dall'elemento utilizzando i tasti di navigazione o la trackball.
onKey()
A partire da View.OnKeyListener. Questo avviene quando l'utente è attivo sull'elemento e preme o rilascia un tasto hardware sul dispositivo.
onTouch()
A partire da View.OnTouchListener. Viene chiamato quando l'utente esegue un'azione qualificata come evento tocco, che include una pressione, un rilascio o un gesto di movimento sullo schermo (entro i limiti dell'elemento).
onCreateContextMenu()
A partire da View.OnCreateContextMenuListener. Questo avviene quando viene creato un menu contestuale (come risultato di un "clic lungo") prolungato. Consulta la discussione sui menu contestuali nella guida per gli sviluppatori Menu.

Questi metodi sono gli unici utenti 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, chiama setOnClickListener() e trasmettila l'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);
    ...
}

Inoltre, potrebbe essere più pratico implementare OnClickListener come parte della tua Attività. In questo modo eviterai il carico aggiuntivo della classe e l'allocazione degli oggetti. 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 quelli che lo fanno, ecco perché:

  • onLongClick(): restituisce un valore booleano che indica se hai utilizzato l'evento e questo non deve essere portato ulteriormente. In altre parole, restituisci true per indicare che hai gestito l'evento e che deve fermarsi qui; restituisce false se non l'hai gestito e/o l'evento deve continuare con qualsiasi altro listener al clic.
  • onKey(): restituisce un valore booleano che indica se hai utilizzato l'evento e questo non deve essere portato ulteriormente. In altre parole, restituisce true per indicare che hai gestito l'evento e che deve fermarsi qui; restituisce false se non l'hai gestito e/o l'evento deve continuare su qualsiasi altro listener sulla chiave.
  • onTouch(): restituisce un valore booleano che indica se il listener utilizza questo evento. La cosa importante è che questo evento può avere più azioni che si susseguono. Di conseguenza, se restituisci false quando viene ricevuto l'evento di azione down, indichi che non hai consumato l'evento e non sei interessato alle azioni successive di questo evento. Di conseguenza, non riceverai altre azioni all'interno dell'evento, come un gesto del dito o l'eventuale evento di azione verso l'alto.

Ricorda che gli eventi chiave hardware vengono sempre inviati nella visualizzazione attualmente attiva. e viene inviato a partire dall'alto della gerarchia delle visualizzazioni e poi verso il basso, fino a raggiungere la destinazione appropriata. Se la tua vista (o una vista secondaria della tua vista) è attualmente attiva, puoi vedere che l'evento si sposta con il metodo dispatchKeyEvent(). In alternativa all'acquisizione di eventi chiave tramite la vista, puoi anche ricevere tutti gli eventi all'interno dell'attività con onKeyDown() e onKeyUp().

Inoltre, quando pensi all'input di testo per la tua applicazione, ricorda che molti dispositivi hanno solo metodi software. Questi metodi non devono essere basati su tasti; 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 un'interfaccia utente che richieda il controllo di pressioni specifiche dei tasti, a meno che tu non voglia limitare l'applicazione ai dispositivi con una tastiera hardware. In particolare, non fare affidamento su questi metodi per convalidare l'input quando l'utente preme la chiave di ritorno; 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 di fare ipotesi su come dovrebbe funzionare un metodo di input software e fidati semplicemente di fornire testo già formattato alla tua applicazione.

Nota: Android chiama prima i gestori di eventi, poi i gestori predefiniti appropriati a partire 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à il callback al gestore di eventi predefinito nella vista. Quindi, assicurati di voler terminare l'evento quando restituisca true.

Gestori di eventi

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

È importante conoscere alcuni altri metodi, che non fanno parte della classe View, ma possono influire direttamente sulla modalità di gestione degli eventi. Per gestire eventi più complessi all'interno di un layout, prendi in considerazione questi altri metodi:

Modalità touch

Quando un utente naviga in un'interfaccia utente con tasti direzionali o una trackball, è necessario impostare lo stato attivo su elementi su cui è possibile intervenire (come i pulsanti), in modo che l'utente possa vedere cosa accetterà l'input. Tuttavia, se il dispositivo dispone di funzionalità touch e l'utente inizia a interagire con l'interfaccia toccandola, non è più necessario evidenziare gli elementi o attivare una determinata vista. Esiste quindi una modalità di interazione chiamata "modalità tocco".

Nel caso di un dispositivo con funzionalità touch, quando l'utente tocca lo schermo, il dispositivo entrerà in modalità tocco. Da questo momento in poi, sarà possibile attivare lo stato attivo solo per le viste per le quali isFocusableInTouchMode() è true, come i widget di modifica del testo. Le altre visualizzazioni toccabili, come i pulsanti, non saranno messe in evidenza quando toccate; attiveranno semplicemente i listener al clic quando vengono premuti.

Ogni volta che un utente preme un tasto direzionale o scorre con una trackball, il dispositivo esce dalla modalità tocco e trova 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à tocco 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à tocco.

Gestione dello stato attivo

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

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

Il movimento dello stato attivo 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 questi casi, 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 viene abbandonato l'elemento attivo. Definisci il valore dell'attributo che sia l'ID della vista a cui deve essere impostato 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 genere, in questo layout verticale, lo spostamento verso l'alto dal primo pulsante non andrebbe da nessuna parte, né lo spostamento 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 nell'interfaccia utente (quando in genere non lo è), aggiungi l'attributo XML android:focusable alla vista nella dichiarazione del layout. Imposta il valore true. Puoi anche dichiarare una vista come attivabile in modalità tocco con android:focusableInTouchMode.

Per richiedere una determinata vista per concentrarti, chiama requestFocus().

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