He investigado mucho para ajustar el diseño cuando el teclado está activo y lo he implementado con éxito, pero el problema surge cuando uso android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
esto en mi etiqueta de actividad en el archivo de manifiesto.
Para esto he usado android:windowSoftInputMode="adjustPan|adjustResize|stateHidden"
con diferentes opciones pero sin suerte.
Después de eso implementé FullScreen
programáticamente y probé varios diseños para trabajar con FullScreen
pero todo en vano.
Hice referencia a estos enlaces y he visto muchas publicaciones aquí relacionadas con este problema:
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.


jo jo
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). El de una sola línea 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);
}
}
Espero que esto ayude a alguien.

LEÓN
Dado que la respuesta ya se eligió 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, todavía uso @android:estilo/Tema.Negro.NoTitleBar.Pantalla completa como parte del tema de la aplicación y estadoVisible|ajustarRedimensionar 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 provino de: Ocultar título en un modo de pantalla completa

johan stuyts
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 está sartén cuando se utiliza 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 programable, el contenido primero se panoramiza en función de su altura original y luego se redimensiona 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 la brecha. 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 deshabilitar la panorámica, pero es posible forzar que el desplazamiento de la panorámica sea 0 cambiando la altura del contenido. Esto se puede hacer en el oyente, porque se ejecuta antes de que tenga lugar la panoramización. Establecer la altura del contenido a la altura disponible da como resultado una experiencia de usuario fluida, es decir, sin parpadeo.
También hice estos cambios. Si alguno de estos presenta problemas, hágamelo saber:
- Determinación conmutada de la altura disponible para usar
getWindowVisibleDisplayFrame
. los Rect
se almacena en caché para evitar un poco de basura innecesaria.
- Permita que el oyente también sea eliminado. Esto es útil cuando reutiliza una actividad para diferentes fragmentos que tienen diferentes requisitos de pantalla completa.
- No distinga entre el teclado mostrado u oculto, pero siempre establezca la altura del contenido a la altura del marco de visualización visible.
Se ha probado en un Nexus 5 y emuladores que ejecutan niveles de API 16-24 con tamaños de pantalla que van desde pequeños a grandes.
El código se ha portado a Kotlin, pero volver a portar 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
}
}
}

hai zhang
Acabo de encontrar una solución simple y confiable si está utilizando el enfoque de la interfaz de usuario del sistema (https://developer.android.com/training/system-ui/immersive.html).
Funciona en el caso de que esté usando View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
por ejemplo, si está utilizando CoordinatorLayout
.
no funcionará para WindowManager.LayoutParams.FLAG_FULLSCREEN
(El que también puedes configurar en el tema con android:windowFullscreen
), pero puede lograr un efecto similar con SYSTEM_UI_FLAG_LAYOUT_STABLE
(que “tiene el mismo efecto visual” de acuerdo con los documentos) y esta solución debería funcionar de nuevo.
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION /* If you want to hide navigation */
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
Lo probé en mi dispositivo con Marshmallow.
La clave es que los teclados virtuales también son una de las ventanas del sistema (como la barra de estado y la barra de navegación), por lo que el WindowInsets
despachado por el sistema contiene información precisa y confiable sobre el mismo.
Para el caso de uso como en DrawerLayout
donde intentamos dibujar detrás de la barra de estado, podemos crear un diseño que ignore solo el recuadro superior y aplique el recuadro inferior que representa el teclado en pantalla.
Aquí está mi costumbre FrameLayout
:
/**
* Implements an effect similar to {@code android:fitsSystemWindows="true"} on Lollipop or higher,
* except ignoring the top system window inset. {@code android:fitsSystemWindows="true"} does not
* and should not be set on this layout.
*/
public class FitsSystemWindowsExceptTopFrameLayout extends FrameLayout {
public FitsSystemWindowsExceptTopFrameLayout(Context context) {
super(context);
}
public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setPadding(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(),
insets.getSystemWindowInsetBottom());
return insets.replaceSystemWindowInsets(0, insets.getSystemWindowInsetTop(), 0, 0);
} else {
return super.onApplyWindowInsets(insets);
}
}
}
Y para usarlo:
<com.example.yourapplication.FitsSystemWindowsExceptTopFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Your original layout here -->
</com.example.yourapplication.FitsSystemWindowsExceptTopFrameLayout>
Teóricamente, esto debería funcionar para cualquier dispositivo sin modificaciones locas, mucho mejor que cualquier truco que intente tomar un 1/3
o 1/4
del tamaño de la pantalla como referencia.
(Requiere API 16+, pero estoy usando la pantalla completa solo en Lollipop+ para dibujar detrás de la barra de estado, por lo que es la mejor solución en este caso).

Abhinav Chauhan
Tenga en cuenta que android:windowSoftInputMode="adjustResize"
no funciona cuando WindowManager.LayoutParams.FLAG_FULLSCREEN
se establece para una actividad. Tienes dos opciones.
-
Desactive el modo de pantalla completa para su actividad. La actividad no cambia de tamaño en el modo de pantalla completa. Puede hacerlo en xml (cambiando el tema de la actividad) o en código Java. Agrega las siguientes líneas en tu método onCreate().
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);`
O
-
Use una forma alternativa de lograr el modo de pantalla completa. Agrega el siguiente código en tu método onCreate().
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);`
Tenga en cuenta que el método 2 solo funciona en Android 4.1 y superior.

Comunidad
Tuve que enfrentar este problema también y tuve un trabajo que verifiqué en HTC one, galaxy s1, s2, s3, note y HTC Sensation.
coloque un oyente de diseño global en la vista raíz de su diseño
mRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener(){
public void onGlobalLayout() {
checkHeightDifference();
}
});
y allí verifiqué la diferencia de altura y si la diferencia de altura de la pantalla es mayor que un tercio de la altura de la pantalla, entonces podemos suponer que el teclado está abierto. lo tomé de esta respuesta.
private void checkHeightDifference(){
// get screen frame rectangle
Rect r = new Rect();
mRootView.getWindowVisibleDisplayFrame(r);
// get screen height
int screenHeight = mRootView.getRootView().getHeight();
// calculate the height difference
int heightDifference = screenHeight - (r.bottom - r.top);
// if height difference is different then the last height difference and
// is bigger then a third of the screen we can assume the keyboard is open
if (heightDifference > screenHeight/3 && heightDifference != mLastHeightDifferece) {
// keyboard visiblevisible
// get root view layout params
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mRootView.getLayoutParams();
// set the root view height to screen height minus the height difference
lp.height = screenHeight - heightDifference;
// call request layout so the changes will take affect
.requestLayout();
// save the height difference so we will run this code only when a change occurs.
mLastHeightDifferece = heightDifference;
} else if (heightDifference != mLastHeightDifferece) {
// keyboard hidden
PFLog.d("[ChatroomActivity] checkHeightDifference keyboard hidden");
// get root view layout params and reset all the changes we have made when the keyboard opened.
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mRootView.getLayoutParams();
lp.height = screenHeight;
// call request layout so the changes will take affect
mRootView.requestLayout();
// save the height difference so we will run this code only when a change occurs.
mLastHeightDifferece = heightDifference;
}
}
Esto probablemente no sea a prueba de balas y tal vez en algunos dispositivos no funcione, pero funcionó para mí y espero que también te ayude.

zayn
Agregar android:fitsSystemWindows="true"
al diseño, y este diseño cambiará de tamaño.
Creo que debe agregar botones dentro de ScrollView y debajo de EditText.
– Balaji Khadake
14 de septiembre de 2011 a las 14:44
Ya he probado muchas opciones que no funciona…
– Vineet Shukla
14/09/2011 a las 15:01
coloque sus botones en un diseño de marco y establezca el peso del diseño de marco en 1 y finalmente use solo
android:windowSoftInputMode="adjustPan"
dime si esto funciona..– Sherif el Khatib
20 de septiembre de 2011 a las 15:19
@VineetShukla, ¿ha encontrado algún ejercicio con pantalla completa?
– Muhammad Babar
29/04/2013 a las 11:00
Tenga en cuenta que no debe usar
adjustResize
yadjustPan
al mismo tiempo, desde el javadoc deandroid.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE
: “Esto no se puede combinar con{@link SOFT_INPUT_ADJUST_PAN}”– Denis Kniazhev
19 de septiembre de 2014 a las 8:54