English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Introduzione
Con il passare del tempo nello sviluppo, è inevitabile incontrare vari problemi.
Sul cammino dello sviluppo Android, la ' tastiera virtuale che blocca il campo di input ' è una grande buca che richiede molto tempo - veniamo a guardare lentamente.
Introduzione
Nel caso più semplice, come illustrato nell'immagine: c'è un EditText nella parte inferiore della pagina. Se non si esegue alcun trattamento, potrebbe essere bloccato dalla tastiera virtuale quando viene aperto.
Il trattamento di questa situazione è molto semplice, è sufficiente impostare il valore di android:windowSoftInputMode su adjustPan o adjustResize nel file AndroidManifest, come segue:
<activity android:name=".MainActivity" android:windowSoftInputMode="adjustPan" > ... </activity>
Di solito, possono risolvere il problema, ovviamente, l'effetto di adjustPan e adjustResize è leggermente diverso.
adjustPan sposta l'intera interfaccia verso l'alto, facendo apparire la casella di input senza cambiare la layout dell'interfaccia;
adjustResize ricontrolla la dimensione dell'interfaccia dopo l'apertura della tastiera soft, equivalente a mostrare il contenuto con una regione di interfaccia più piccola, quindi naturalmente la casella di input è inclusa.
↑↑↑ OK, questo è solo un inizio, praticamente tutti gli ingegneri Android sulla Terra possono gestirlo.
Non preoccuparti, guarda sotto~
Aggiungi WebView e vedi? Arriva il buco…
Nell'introduzione sopra, la tastiera soft è stata attivata dal EditText nativo. Mentre H5 e Hybrid sono diventati quasi lo standard delle App, spesso ci si incontra con la situazione in cui: la tastiera soft è attivata dagli elementi web della WebView.
Descrizione della situazione
In questo momento, la situazione si complica:
Prima di tutto, quando la pagina non è in modalità a schermo intero, impostare adjustPan sull'activity non funzionerà.
In secondo luogo, quando la pagina è in modalità a schermo intero, adjustPan e adjustResize non funzionano.
—— spiegazione, qui la modalità a schermo intero si riferisce a una pagina a schermo intero, inclusi Application o activity che utilizzano il tema Fullscreen, utilizzano "colorazione dello stato", "barra di stato immersiva", "Modalità immersiva" e così via - insomma, praticamente qualsiasi App che si prende cura del controllo della barra di stato produrrà questo problema.
La seguente tabella può elencare brevemente i casi specifici.
Perché si dice che è un buco “issue 5497”?
La situazione elencata nella tabella sopra non è quella che Google desidera, il caso ideale sarebbe che tutte le opzioni funzionassero correttamente - quindi questo è in realtà un BUG del sistema Android stesso.
Perché all'inizio dell'articolo si dice che è un buco?
—— poiché questo BUG è stato segnalato sin dalla versione Android 1.x (2009) e non è stato risolto nemmeno fino ad Android 7.0 (2016)…/(╯°□°)╯︵ ┻━┻
Si può dire che non è solo un problema, ma anche un buco scavato ufficialmente~
“issue 5497”,dettagli sul link ☞ Issue 5497 - android -WebView adjustResize windowSoftInputMode breaks when activity is fullscreen - Android Open Source Project - Issue Tracker - Google Project Hosting
Naturalmente, non importa chi ha scavato il problema, alla fine è lo sviluppatore che deve risolverlo.
Dopo aver incontrato il problema, ci sono due modi per superarlo: evitare o risolverlo.
Posizione di evitamento
Come indicato nel testo precedente, le condizioni per la formazione del problema sono: l'activity con WebView utilizza la modalità full-screen o adjustPan.
Allora la posizione per nascondere il problema è molto semplice -
Se ci sono WebView nell'activity, non utilizzare la modalità full-screen e impostare il valore di windowSoftInputMode su adjustResize.
Come, non è molto semplice?
Ma ci sono momenti in cui è necessario ottenere sia la modalità full-screen che WebView, in questi casi, nascondere il problema non funziona, dobbiamo trovare una nuova posizione per risolverlo. Fortunatamente, la saggezza degli sviluppatori è infinita, questo problema è esistito per così tanti anni, e qualcuno ha trovato alcune soluzioni.
AndroidBug5497Workaround
Personalmente penso che la soluzione migliore sia questa:AndroidBug5497Workaroundbasta una magica classe AndroidBug5497Workaround.
Dal nome si capisce che è dedicato a risolvere il problema “5497”, il modo di utilizzo è anche molto semplice:
Copia la classe AndroidBug5497Workaround nel progetto
Aggiungi una frase AndroidBug5497Workaround.assistActivity(this) nel metodo onCreate dell'activity che necessita di essere risolta.
Secondo il test, è disponibile基本上 su tutte le versioni di Android, l'effetto è quasi equivalente a impostare adjustResize.
Guardiamo un'immagine di confronto:
Un'Activity di full-screen mode utilizzando WebView della nostra App, dall'alto in basso: senza tastiera soft, l'effetto di copertura della casella di input dalla tastiera soft, e l'effetto finale dopo l'uso di AndroidBug5497Workaround.
Qual è il suo principio?
Questa classe AndroidBug5497Workaround, che sembra affascinante, in realtà non è molto complessa, ha solo alcune decine di righe di codice, vediamo prima di tutto:
public class AndroidBug5497Workaround { // Per ulteriori informazioni, vedere https://code.google.com/p/android/issues/detail?id=5497 // Utilizzare questa classe è semplice, basta invocare assistActivity() su un Activity che ha già impostato la sua vista di contenuto. public static void assistActivity (Activity activity) {}} new AndroidBug5497Workaround(activity); } private View mChildOfContent; private int usableHeightPrevious; private FrameLayout.LayoutParams frameLayoutParams; private AndroidBug5497Workaround(Activity activity) { FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content); mChildOfContent = content.getChildAt(0); mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { public void onGlobalLayout() { possiblyResizeChildOfContent(); } }); frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams(); } private void possiblyResizeChildOfContent() { int usableHeightNow = computeUsableHeight(); if (usableHeightNow != usableHeightPrevious) { int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight(); int heightDifference = usableHeightSansKeyboard - usableHeightNow; if (heightDifference > (usableHeightSansKeyboard/4)) { // tastiera probabilmente è stata resa visibile frameLayoutParams.height = usableHeightSansKeyboard - heightDifference; } else { // tastiera probabilmente è stata nascosta frameLayoutParams.height = usableHeightSansKeyboard; } mChildOfContent.requestLayout(); usableHeightPrevious = usableHeightNow; } } private int computeUsableHeight() { Rect r = new Rect(); mChildOfContent.getWindowVisibleDisplayFrame(r); return (r.bottom - r.top); // In modalità a schermo intero: return r.bottom } }
Il codice fa più o meno queste cose:
1. Trovare il View radice dell'activity
Guardiamo il codice di ingresso:
FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content); mChildOfContent = content.getChildAt(0);
Tra cui, il View indicato da android.R.id.content nella prima riga è il View radice che i developer possono controllare su tutte le interfacce Activity di Android.
Se l'Activity è in modalità a schermo intero, android.R.id.content occupa l'intera area del display.
Se l'Activity è un modello non a schermo intero, android.R.id.content occupa l'intera area tranne la barra di stato.
In altre circostanze, come Activity in una finestra di dialogo, o lo stile a schermo diviso dopo il 7.0, android.R.id.content è il raggio di una finestra di dialogo o la metà dello schermo dello stile a schermo diviso - queste circostanze sono rare, quindi non li consideriamo per ora.
Quello che usiamo spesso setContentView(View view)/setContent(int layRes) è mettere il View o layRes specificato dentro android.R.id.content, diventandone un subView.
Quindi, quindi, la seconda riga content.getChildAt(0) ottiene mChildOfContent, che è proprio quello che serve per ottenere il View che abbiamo messo dentro con setContentView.
2. Impostare un Listener per monitorare le modifiche del View tree
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener({ // Sintassi semplificata possiblyResizeChildOfContent(); });
View.getViewTreeObserver() può ottenere un oggetto ViewTreeObserver - questo oggetto è un osservatore, specificamente utilizzato per monitorare alcune modifiche nel View tree corrente. L'addOnGlobalLayoutListener registrato qui è chiamato quando il layout globale (GlobalLayout) del View tree corrente cambia o lo stato visibile dei View cambia, avvisando tramite una chiamata di ritorno.
—— 'tastiera soft aperta', è una sorgente che può scatenare questo evento. (L'apertura della tastiera soft può causare la modifica di GlobalLayout)
Quindi, ora possiamo monitorare l'evento 'tastiera soft aperta'.
3. Ottenere l'altezza 'disponibile' dopo che l'interfaccia è cambiata
Dopo che la tastiera soft si è aperta, la cosa successiva è ottenere l'altezza disponibile dell'interfaccia dopo la modifica (che può essere utilizzata dai sviluppatori per visualizzare il contenuto).
Guarda il codice direttamente:
private int computeUsableHeight() { Rect rect = new Rect(); mChildOfContent.getWindowVisibleDisplayFrame(rect); // rect.top è l'altezza della barra di stato, se è un tema a schermo intero, puoi semplicemente return rect.bottom return (rect.bottom - rect.top); }
View.getWindowVisibleDisplayFrame(Rect rect), questa riga di codice può ottenere il Rect - è la regione rettangolare rimasta dell'interfaccia, dopo aver rimosso la barra dei titoli e la parte coperta dalla tastiera soft, come illustrato nella figura, l'area tra le cornici rosse.
Diagramma illustrativo dell'area Rect
Possiamo anche vedere:
Il valore di rect.top è in realtà l'altezza della barra dei titoli. (In effetti, questo viene spesso utilizzato come metodo per ottenere l'altezza della barra dei titoli)
L'altezza dello schermo - rect.bottom è l'altezza della tastiera soft. (Il metodo per ottenere l'altezza della tastiera soft è anche apparso)
In questo momento, abbiamo:
In modalità a schermo intero, altezza disponibile = rect.bottom
In modalità non a schermo intero, altezza disponibile = rect.bottom - rect.top
4. Ultimo passo, reimpostare l'altezza
L'altezza disponibile calcolata è l'altezza dell'interfaccia visibile in termini di effetto visivo. Tuttavia, l'altezza effettiva dell'interfaccia attuale è maggiore dell'altezza disponibile di una distanza per la tastiera soft.
Quindi, l'ultimo passo è impostare l'altezza dell'interfaccia utente sull'altezza disponibile - il lavoro è completato.
private void possiblyResizeChildOfContent() { int usableHeightNow = computeUsableHeight(); if (usableHeightNow != usableHeightPrevious) { int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight(); int heightDifference = usableHeightSansKeyboard - usableHeightNow; if (heightDifference > (usableHeightSansKeyboard/4)) { // tastiera probabilmente è stata resa visibile frameLayoutParams.height = usableHeightSansKeyboard - heightDifference; } else { // tastiera probabilmente è stata nascosta frameLayoutParams.height = usableHeightSansKeyboard; } mChildOfContent.requestLayout(); usableHeightPrevious = usableHeightNow; } }
Nel codice è stata aggiunta una condizione "heightDifference > (usableHeightSansKeyboard/4)" per eliminare le interferenze inutili. Poiché ci sono molte ragioni che possono far scattare l'evento OnGlobalLayout, non solo il cambiamento di visualizzazione della tastiera, ma anche le variazioni di visibilità dei vari subView, che hanno un impatto limitato sull'altezza dell'interfaccia. Con questa condizione, solo quando la variazione dell'altezza dell'interfaccia supera 1/4 dell'altezza dello schermo, verrà eseguito il riimpostaggio dell'altezza, garantendo che il codice risponda solo al cambiamento di visualizzazione della tastiera.
Riassunto
Riassumendo, è così:
Activity normale (senza WebView), utilizzare direttamente adjustpan o adjustResize
Se è presente WebView:
a) Se non è in modalità a schermo intero, è possibile utilizzare adjustResize
b) Se è in modalità a schermo intero, utilizzare AndroidBug5497Workaround per la gestione.
Come già descritto dall'autore, la soluzione definitiva per bloccare la tastiera Android sugli input box è stata presentata. Spero che sia utile a tutti. Se avete domande, lasciate un commento e l'autore risponderà prontamente. In questo senso, anche un grande ringraziamento per il supporto al sito di tutorial di urla!
Dichiarazione: il contenuto di questo articolo è stato raccolto da Internet, il copyright spetta ai rispettivi proprietari, il contenuto è stato contribuito e caricato autonomamente dagli utenti di Internet, questo sito non detiene i diritti di proprietà, non è stato editato manualmente e non assume alcuna responsabilità legale. Se trovi contenuti sospetti di violazione del copyright, ti preghiamo di inviare una e-mail a: notice#oldtoolbag.com (al momento dell'invio dell'e-mail, sostituisci # con @) per segnalare il problema e fornire prove pertinenti. Una volta verificata, questo sito rimuoverà immediatamente il contenuto sospetto di violazione del copyright.