2013-02-15 6 views
7

Nella maggior parte dei casi, desidero che gli eventi chiave vengano elaborati dalla vista (secondaria) che attualmente ha il focus, che è il comportamento predefinito, ed è anche ciò che attualmente ho implementato.In Android, una persona può intercettare gli eventi chiave a livello globale prima che raggiungano la vista del bambino che ha l'attenzione?

Tuttavia, in determinate circostanze molto specifiche, vorrei intercettare temporanea e gestire tutti gli eventi chiave (tra cui in particolare quelli normalmente gestito dalla vista dei bambini) sia nella mia attività in corso o, in mancanza di questo, a mio avviso root (esso non importa, a patto che vengano elaborati globalmente - non mi importa dei pulsanti hardware come volume +/-, in quanto non sono comunque gestiti in nessuna delle visioni di mio figlio).

Per tocco eventi, abbiamo onInterceptTouchEvent(), che permette un ViewGroup per seguire gli eventi di tocco come esse vengono inviate in vista del bambino, e per bloccare la ricezione di quegli eventi (se si desidera) dalla vista dei bambini per i quali sono sono intesi.

Sfortunatamente, non riesco a trovare nulla di analogo a onInterceptTouchEvent() per eventi chiave. Mi manca qualcosa di ovvio, o si tratta di una vera e propria asimmetria nel sistema operativo?

Ovviamente, potrei semplicemente collegare il codice di gestione eventi chiave corrente di ogni vista figlio per chiamare direttamente un metodo sull'attività principale per gestire l'evento se lo desidera, e per fare in modo che il metodo a livello di attività restituisca un valore booleano che indica se ha gestito l'evento. Quindi, la vista figlio poteva gestire l'evento se e solo se il metodo di attività invocato aveva non gestito da.

Ma spero che ci sia un modo più semplice per intercettare semplicemente il traffico sulla sua strada "in basso" dalla gerarchia alla vista figlio, proprio come onInterceptTouchEvent() fa per gli eventi di tocco.

+1

Nota che sono anche interessato alle risposte che affermano che questo * non può * essere fatto. Se verificato, anche questa risposta potrebbe essere accettata. – Carl

+0

Sono anche curioso di sapere perché questa funzionalità esisterebbe per gli eventi tattili, ma non per gli eventi chiave, se è davvero così. – Carl

risposta

0

Tutti i widget/Vista sembrano implementare KeyEvent.Callback, che ha metodi di essere chiamato per la chiave verso il basso, premere a lungo, multiple e tasto su. Tutti questi metodi restituiscono valori booleani spiegato come:

Se ha gestito l'evento, restituisce true. Se si desidera consentire che l'evento venga gestito dal ricevitore successivo, restituire false.

penso che si può provare l'override questi metodi nei componenti principali.

L'altro è dispatchKeyEvent() di View gestisce gli eventi di dispacciamento lungo il percorso di messa a fuoco. Sovrascrivere questo può essere provato anche.

+0

Grazie per la risposta. 1) A meno che non mi sbagli, i metodi dichiarati dall'interfaccia KeyEvent.Callback, come onKeyDown(), vengono invocati per primi per la vista che al momento ha lo stato attivo. È solo se quella vista restituisce false da uno di questi metodi che altre viste, antenati, ottengono. Mi interessa avere la vista radice (o l'attività) accedere agli eventi * prima * della vista che ha il focus. 2) Credo che dispatchKeyEvent() * generi * un evento chiave a livello di codice. Quello che sto cercando di fare è * intercettare * un evento generato come risultato del * utente * che ha toccato un tasto della tastiera. – Carl

+0

Capisco. Che ne dici di afferrare e mantenere l'attenzione? –

+0

Hmm, sì, posso vedere come alcune persone che affrontano un problema simile potrebbero prendere l'approccio, per esempio, chiamando setFocusable (false) per le visualizzazioni figlio in questione, se questo è quello che hai in mente. Il problema con questo per me è che voglio che l'utente possa continuare a usare il tocco in quelle viste per selezionare e navigare. Voglio solo disabilitare l'elaborazione di input da tastiera da quelle viste figlio e sostituirla con l'elaborazione globale delle stesse sequenze di tasti, quando vengono rilevate determinate condizioni (a livello globale). – Carl

0

Ignora dispatchKeyEvent in un ViewGroup che è ancestrale al View s per essere disattivato funziona.

Sto usando il seguente ~.

public static class TvPrefsContainer extends FrameLayout { 
    private boolean isActive; // i.e. will dispatch keyboard events to focused children 
    // snip 

    @Override public boolean dispatchKeyEvent(KeyEvent event) { 
     return isActive && super.dispatchKeyEvent(event); 
    } 
} 

public static class TvPrefs extends PreferenceFragment { 
    @Override public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     addPreferencesFromResource(R.xml.tv_prefs); 
    } 
} 

private void togglePrefsVis() { 
    tvPrefsContainer.animate() 
      .alpha(isPrefsVisible ? 0 : 1) 
      .translationX(isPrefsVisible ? tvPrefsContainer.getMeasuredWidth() : 0) 
      .start(); 
    tvPrefsContainer.isActive = isPrefsVisible; 
    isPrefsVisible = !isPrefsVisible; 
} 
+0

Ho sbagliato su 'isActivated'. Per lo meno contribuisce agli stati utilizzati per StateListDrawables – nmr

+0

Penso che dispatchKeyEventPreIme (http://developer.android.com/reference/android/view/ViewGroup.html#dispatchKeyEventPreIme(android.view.KeyEvent)) sarà più utile – Grimmy

0

È possibile aggiungere OnGlobalFocusChangeListener alla visualizzazione principale. Facciamolo per attività:

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    findViewById(android.R.id.content).getViewTreeObserver().addOnGlobalFocusChangeListener(new ViewTreeObserver.OnGlobalFocusChangeListener() { 
     @Override 
     public void onGlobalFocusChanged(View oldFocus, View newFocus) { 
      if (newFocus instanceof EditText) { 
       ((EditText) newFocus).addTextChangedListener(new TextWatcher() { 
        @Override 
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { 
         //process whatever you want 
        } 

        @Override 
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { 
        } 

        @Override 
        public void afterTextChanged(Editable editable) { 
        } 
       }); 
      } 
     } 
    }); 
} 

Naturalmente se siete interessati a vista diversi EditText si deve capire come osservare i loro cambiamenti.

Inoltre, se si desidera aggiungerlo globalmente a tutte le attività, utilizzare Application#registerActivityLifecycleCallbacks() per utilizzare tale codice in tutte le attività.

Problemi correlati