Android Cómo ajustar el diseño en modo de pantalla completa cuando el teclado está visible
He investigado mucho para ajustar el diseño cuando el teclado virtual está activo y lo he implementado con éxito, pero el problema surge cuando usoandroid:theme="@android:style/Theme.NoTitleBar.Fullscreen"
esto en mi etiqueta de actividad en el archivo de manifiesto.
Para esto he usadoandroid:windowSoftInputMode="adjustPan|adjustResize|stateHidden"
con diferentes opciones pero no tuve suerte.
Después de eso, implementé FullScreen
mediante programación y probé varios diseños para trabajar.FullScreen
pero todo fue en vano.
Mencioné estos enlaces y he buscado muchas publicaciones aquí relacionadas con este tema:
http://android-developers.blogspot.com/2009/04/updating-applications-for-on-screen.html
http://davidwparker.com/2011/08/30/android-how-to-float-a-row-above-keyboard/
Aquí está el código xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="@+id/masterContainerView"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#ffffff">
<ScrollView android:id="@+id/parentScrollView"
android:layout_width="fill_parent" android:layout_height="wrap_content">
<LinearLayout android:layout_width="fill_parent"
android:layout_height="fill_parent" android:orientation="vertical">
<TextView android:id="@+id/setup_txt" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="Setup - Step 1 of 3"
android:textColor="@color/top_header_txt_color" android:textSize="20dp"
android:padding="8dp" android:gravity="center_horizontal" />
<TextView android:id="@+id/txt_header" android:layout_width="fill_parent"
android:layout_height="40dp" android:text="AutoReply:"
android:textColor="@color/top_header_txt_color" android:textSize="14dp"
android:textStyle="bold" android:padding="10dp"
android:layout_below="@+id/setup_txt" />
<EditText android:id="@+id/edit_message"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:text="Some text here." android:textSize="16dp"
android:textColor="@color/setting_editmsg_color" android:padding="10dp"
android:minLines="5" android:maxLines="6" android:layout_below="@+id/txt_header"
android:gravity="top" android:scrollbars="vertical"
android:maxLength="132" />
<ImageView android:id="@+id/image_bottom"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:layout_below="@+id/edit_message" />
</LinearLayout>
</ScrollView>
<RelativeLayout android:id="@+id/scoringContainerView"
android:layout_width="fill_parent" android:layout_height="50px"
android:orientation="vertical" android:layout_alignParentBottom="true"
android:background="#535254">
<Button android:id="@+id/btn_save" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_alignParentRight="true"
android:layout_marginTop="7dp" android:layout_marginRight="15dp"
android:layout_below="@+id/edit_message"
android:text = "Save" />
<Button android:id="@+id/btn_cancel" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_marginTop="7dp"
android:layout_marginRight="10dp" android:layout_below="@+id/edit_message"
android:layout_toLeftOf="@+id/btn_save" android:text = "Cancel" />
</RelativeLayout>
</RelativeLayout>
Quiero que los 2 botones inferiores vayan hacia arriba cuando aparezca el teclado virtual.
Basado en la solución alternativa de yghm , codifiqué una clase de conveniencia que me permite resolver el problema con una sola línea (después de agregar la nueva clase a mi código fuente, por supuesto). La frase es:
AndroidBug5497Workaround.assistActivity(this);
Y la clase de implementación es:
public class AndroidBug5497Workaround {
// For more information, see https://issuetracker.google.com/issues/36911528
// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
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)) {
// keyboard probably just became visible
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
} else {
// keyboard probably just became hidden
frameLayoutParams.height = usableHeightSansKeyboard;
}
mChildOfContent.requestLayout();
usableHeightPrevious = usableHeightNow;
}
}
private int computeUsableHeight() {
Rect r = new Rect();
mChildOfContent.getWindowVisibleDisplayFrame(r);
return (r.bottom - r.top);
}
}
Como ya se seleccionó la respuesta y se sabe que el problema es un error, pensé en agregar una "Posible solución alternativa".
Puede alternar el modo de pantalla completa cuando se muestra el teclado virtual. Esto permite que "adjustPan" funcione correctamente.
En otras palabras, sigo usando @android:style/Theme.Black.NoTitleBar.Fullscreen como parte del tema de la aplicación y stateVisible|adjustResize como parte del modo de entrada suave de la ventana de actividad, pero para que funcionen juntos debo alternar el modo de pantalla completa. antes de que aparezca el teclado.
Utilice el siguiente código:
Desactivar el modo de pantalla completa
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
Activar el modo de pantalla completa
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
Nota: la inspiración vino de: Ocultar título en modo de pantalla completa
Probé la solución de Joseph Johnson , pero al igual que otros, me encontré con el problema de la brecha entre el contenido y el teclado. El problema ocurre porque el modo de entrada suave siempre es panorámico cuando se usa el modo de pantalla completa. Esta panorámica interfiere con la solución de Joseph cuando activa un campo de entrada que estaría oculto por la entrada suave.
Cuando aparece la entrada suave, el contenido primero se desplaza según su altura original y luego se cambia el tamaño según el diseño solicitado por la solución de Joseph. El cambio de tamaño y el diseño posterior no deshacen la panorámica, lo que da como resultado el espacio. El orden completo de los eventos es:
- Oyente de diseño global
- Panorámica
- Diseño del contenido (= cambio de tamaño real del contenido)
No es posible desactivar la panorámica, pero es posible forzar el desplazamiento de la panorámica a 0 cambiando la altura del contenido. Esto se puede hacer en el oyente, porque se ejecuta antes de que se realice la panorámica. Configurar la altura del contenido a la altura disponible da como resultado una experiencia de usuario fluida, es decir, sin parpadeos.
También hice estos cambios. Si alguno de estos presenta problemas, hágamelo saber:
- Determinación cambiada de la altura disponible para usar
getWindowVisibleDisplayFrame
. SeRect
almacena en caché para evitar un poco de basura innecesaria. - Permita que el oyente también sea eliminado. Esto resulta útil cuando reutiliza una actividad para diferentes fragmentos que tienen diferentes requisitos de pantalla completa.
- No distinga entre teclado mostrado u oculto, pero establezca siempre la altura del contenido en la altura del marco de visualización visible.
Se ha probado en un Nexus 5 y en emuladores que ejecutan niveles API 16-24 con tamaños de pantalla que van desde pequeños hasta grandes.
El código se ha portado a Kotlin, pero trasladar mis cambios a Java es sencillo. Déjame saber si necesitas ayuda:
class AndroidBug5497Workaround constructor(activity: Activity) {
private val contentContainer = activity.findViewById(android.R.id.content) as ViewGroup
private val rootView = contentContainer.getChildAt(0)
private val rootViewLayout = rootView.layoutParams as FrameLayout.LayoutParams
private val viewTreeObserver = rootView.viewTreeObserver
private val listener = ViewTreeObserver.OnGlobalLayoutListener { possiblyResizeChildOfContent() }
private val contentAreaOfWindowBounds = Rect()
private var usableHeightPrevious = 0
// I call this in "onResume()" of my fragment
fun addListener() {
viewTreeObserver.addOnGlobalLayoutListener(listener)
}
// I call this in "onPause()" of my fragment
fun removeListener() {
viewTreeObserver.removeOnGlobalLayoutListener(listener)
}
private fun possiblyResizeChildOfContent() {
contentContainer.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds)
val usableHeightNow = contentAreaOfWindowBounds.height()
if (usableHeightNow != usableHeightPrevious) {
rootViewLayout.height = usableHeightNow
// Change the bounds of the root view to prevent gap between keyboard and content, and top of content positioned above top screen edge.
rootView.layout(contentAreaOfWindowBounds.left, contentAreaOfWindowBounds.top, contentAreaOfWindowBounds.right, contentAreaOfWindowBounds.bottom)
rootView.requestLayout()
usableHeightPrevious = usableHeightNow
}
}
}
Tenga en cuenta que android:windowSoftInputMode="adjustResize"
no funciona cuando WindowManager.LayoutParams.FLAG_FULLSCREEN
está configurado para una actividad. Tienes dos opciones.
Deshabilite el modo de pantalla completa para su actividad. La actividad no cambia de tamaño en el modo de pantalla completa. Puedes hacer esto en xml (cambiando el tema de la actividad) o en código Java. Agregue las siguientes líneas en su método onCreate().
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);`
O
Use an alternative way to achieve fullscreen mode. Add the following code in your onCreate() method.
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); View decorView = getWindow().getDecorView(); // Hide the status bar. int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN; decorView.setSystemUiVisibility(uiOptions);`
Please note that method-2 only works in Android 4.1 and above.