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
e trasmettila l'implementazione di setOnClickListener()
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é:
: 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.onLongClick()
: 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.onKey()
: 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.onTouch()
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
. In alternativa all'acquisizione di eventi chiave tramite la vista, puoi anche ricevere tutti gli eventi all'interno dell'attività con dispatchKeyEvent()
e onKeyDown()
.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
. 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 onKeyDown()
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:
: chiamata quando si verifica un nuovo evento chiave.onKeyDown(int, KeyEvent)
- Richiamato quando si verifica un evento chiave.onKeyUp(int, KeyEvent)
: chiamato quando si verifica un evento di trackball.onTrackballEvent(MotionEvent)
: chiamata quando si verifica un evento di movimento del touchscreen.onTouchEvent(MotionEvent)
- Richiamato quando la visualizzazione acquisisce o perde la messa a fuoco.onFocusChanged(boolean, int, Rect)
È 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:
: in questo modo il tuoActivity.dispatchTouchEvent(MotionEvent)
Activity
può intercettare tutti gli eventi tocco prima che vengano inviati alla finestra.
: in questo modo,ViewGroup.onInterceptTouchEvent(MotionEvent)
ViewGroup
può guardare gli eventi inviati alle viste secondarie.
: richiama una vista principale per indicare che non deve intercettare gli eventi touch conViewParent.requestDisallowInterceptTouchEvent(boolean)
.onInterceptTouchEvent(MotionEvent)
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
. Per modificare l'impostazione dello stato attivo per
una vista, chiama isFocusable()
. In modalità tocco, puoi chiedere se una vista consente lo stato attivo con setFocusable()
.
Puoi cambiare questa opzione con isFocusableInTouchMode()
.
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
,
come descritto nella sezione Listener di eventi.onFocusChange()