Android Cómo ajustar el diseño en Modo de pantalla Completa cuando softkeyboard está visible
He investigado mucho para ajustar el diseño cuando softkeyboard está activo y lo he implementado con éxito, pero el problema viene 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.
Me referí a estos enlaces y he buscado muchos mensajes aquí relacionados con esto cuestión:
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 el softkeyboard aparezca en la imagen.
23 answers
-> https://groups.google.com/group/android-developers/msg/5690ac3a9819a53b?pli=1
- > el modo de pantalla completa no cambia de tamaño
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-15 23:26:17
Basado en la solución alternativa de yghm, codifiqué una clase convenience que me permite resolver el problema con una línea única (después de agregar la nueva clase a mi código fuente, por supuesto). La única 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.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-10 14:50:37
Dado que la respuesta ya se ha elegido y el problema se sabe que es un error, pensé que podría agregar un "Posible Trabajo Alrededor".
Puede alternar el modo de pantalla completa cuando se muestra el teclado de software. Esto permite que el" 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 stateVisible / adjustResize como parte de la ventana de actividad modo de entrada suave, pero para obtener para trabajar 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 el título en modo de pantalla completa
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:59
Probé la solución de Joseph Johnson, pero como otros me encontré con el problema de la brecha entre el contenido y el teclado. El problema se produce porque el modo de entrada suave es siempre pan cuando se utiliza el modo de pantalla completa. Esta panorámica interfiere con la solución de Joseph cuando se activa un campo de entrada que estaría oculto por la entrada suave.
Cuando aparece la entrada suave, el contenido se desplaza primero en función de su altura original, y luego cambia el tamaño por el diseño solicitado por el La solución de Joseph. El cambio de tamaño y el diseño posterior no deshacen la panorámica, lo que resulta en el espacio. El orden completo de los eventos es:
- Oyente de diseño global
- Panorámica
- Diseño del contenido (= redimensionamiento real del contenido)
No es posible desactivar la panorámica, pero es posible forzar el desplazamiento de panorámica a 0 cambiando la altura del contenido. Esto se puede hacer en el oyente, porque se ejecuta antes de que tenga lugar la panorámica. Configuración de la 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 conmutada de la altura disponible a utilizar
getWindowVisibleDisplayFrame
. ElRect
se almacena en caché para evitar un poco de basura innecesaria. - Permite que el oyente también se elimine. Esto es útil cuando reutiliza una actividad para diferentes fragmentos que tienen diferentes requisitos de pantalla completa.
- Do no distinga entre el teclado mostrado u oculto, pero establezca siempre 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 ha sido portado a Kotlin, pero portar mis cambios a Java es simple. Avísame 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 = { 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
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:59
Tuve que enfrentar este problema también y tenía un trabajo alrededor del cual comprobé en HTC uno, galaxy s1, s2, s3, nota y HTC sensation.
Ponga 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í comprobé la diferencia de altura y si la diferencia de altura de la pantalla es mayor que un tercio en la altura de la pantalla, entonces podemos asumir 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 es a prueba de balas y tal vez en algunos dispositivos no funcionará, pero funcionó para mí y espero que te ayude también.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:47
Tenga en cuenta que android:windowSoftInputMode="adjustResize"
no funciona cuando WindowManager.LayoutParams.FLAG_FULLSCREEN
está configurado para una actividad. Tienes dos opciones.
-
O bien desactivar el modo de pantalla completa para su actividad. La actividad no se redimensiona en el modo de pantalla completa. Puede hacerlo 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
-
Utilice una forma alternativa de lograr el modo de pantalla completa. Añadir el siguiendo el 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 method-2 solo funciona en Android 4.1 y superior.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-31 05:40:53
Implementé la solución Joseph Johnson y funcionó bien, me di cuenta después de usar esta solución a veces el cajón de la aplicación no se cerrará correctamente. He añadido una funcionalidad para eliminar el listener removeOnGlobalLayoutListener cuando el usuario cierra el fragmento donde se encuentran edittexts.
//when the application uses full screen theme and the keyboard is shown the content not scrollable!
//with this util it will be scrollable once again
//http://stackoverflow.com/questions/7417123/android-how-to-adjust-layout-in-full-screen-mode-when-softkeyboard-is-visible
public class AndroidBug5497Workaround {
private static AndroidBug5497Workaround mInstance = null;
private View mChildOfContent;
private int usableHeightPrevious;
private FrameLayout.LayoutParams frameLayoutParams;
private ViewTreeObserver.OnGlobalLayoutListener _globalListener;
// For more information, see https://code.google.com/p/android/issues/detail?id=5497
// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
public static AndroidBug5497Workaround getInstance (Activity activity) {
if(mInstance==null)
{
synchronized (AndroidBug5497Workaround.class)
{
mInstance = new AndroidBug5497Workaround(activity);
}
}
return mInstance;
}
private AndroidBug5497Workaround(Activity activity) {
FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
mChildOfContent = content.getChildAt(0);
frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
_globalListener = new ViewTreeObserver.OnGlobalLayoutListener()
{
@Override
public void onGlobalLayout()
{
possiblyResizeChildOfContent();
}
};
}
public void setListener()
{
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(_globalListener);
}
public void removeListener()
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mChildOfContent.getViewTreeObserver().removeOnGlobalLayoutListener(_globalListener);
} else {
mChildOfContent.getViewTreeObserver().removeGlobalOnLayoutListener(_globalListener);
}
}
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);
}
}
Utiliza la clase donde se encuentra mi edittexts
@Override
public void onStart()
{
super.onStart();
AndroidBug5497Workaround.getInstance(getActivity()).setListener();
}
@Override
public void onStop()
{
super.onStop();
AndroidBug5497Workaround.getInstance(getActivity()).removeListener();
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-16 09:39:13
Acabo de encontrar una solución simple y confiable si está utilizando el enfoque de interfaz de usuario del sistema ( https://developer.android.com/training/system-ui/immersive.html).
Funciona en el caso de que esté utilizando View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
, por ejemplo, si está utilizando CoordinatorLayout
.
No funcionará para WindowManager.LayoutParams.FLAG_FULLSCREEN
(El que también puede configurar en tema con android:windowFullscreen
), pero puede lograr un efecto similar con SYSTEM_UI_FLAG_LAYOUT_STABLE
(que "tiene el mismo efecto visual" según los documentos ) y esta solución debería funcionar 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 he probado en mi dispositivo ejecutando Marshmallow.
La clave es que los teclados suaves 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
enviado por el sistema contiene información precisa y confiable al respecto.
Para el caso de uso como en DrawerLayout
donde estamos tratando de 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 recuadro suave teclado.
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>
Esto debería funcionar teóricamente para cualquier dispositivo sin modificaciones dementes, mucho mejor que cualquier hack que intente tomar un 1/3
o 1/4
aleatorio del tamaño de la pantalla como referencia.
(Requiere API 16+, pero estoy usando 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.)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-19 10:16:13
Para que funcione con pantalla completa:
Utilice el plugin ionic keyboard. Esto le permite escuchar cuando el teclado aparece y desaparece.
OnDeviceReady agregue estos oyentes de eventos:
// Allow Screen to Move Up when Keyboard is Present
window.addEventListener('native.keyboardshow', onKeyboardShow);
// Reset Screen after Keyboard hides
window.addEventListener('native.keyboardhide', onKeyboardHide);
La Lógica:
function onKeyboardShow(e) {
// Get Focused Element
var thisElement = $(':focus');
// Get input size
var i = thisElement.height();
// Get Window Height
var h = $(window).height()
// Get Keyboard Height
var kH = e.keyboardHeight
// Get Focused Element Top Offset
var eH = thisElement.offset().top;
// Top of Input should still be visible (30 = Fixed Header)
var vS = h - kH;
i = i > vS ? (vS - 30) : i;
// Get Difference
var diff = (vS - eH - i);
if (diff < 0) {
var parent = $('.myOuter-xs.myOuter-md');
// Add Padding
var marginTop = parseInt(parent.css('marginTop')) + diff - 25;
parent.css('marginTop', marginTop + 'px');
}
}
function onKeyboardHide(e) {
// Remove All Style Attributes from Parent Div
$('.myOuter-xs.myOuter-md').removeAttr('style');
}
Básicamente si la diferencia es menos entonces esa es la cantidad de píxeles que el teclado está cubriendo de su entrada. Así que si usted ajusta su div padre por esto que debe contrarrestarlo.
Agregar tiempos de espera a la lógica dice que 300ms debería también optimizar el rendimiento (ya que esto permitirá que aparezca el tiempo del teclado.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-11 10:40:45
Solo use android:windowSoftInputMode="adjustResize|stateHidden
mientras usa adjustPan, luego deshabilite la propiedad de redimensionamiento
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-20 06:35:29
Probé la clase de Joseph Johnson, y funcionó, pero no satisfizo mis necesidades. En lugar de emular android:windowSoftInputMode="adjustResize", necesitaba emular android:windowSoftInputMode="adjustPan".
Estoy usando esto para una vista web a pantalla completa. Para desplazar la vista de contenido a la posición correcta, necesito usar una interfaz javascript que proporcione detalles sobre la posición del elemento de página que tiene foco y, por lo tanto, está recibiendo la entrada del teclado. He omitido esos detalles, pero proporcionó mi reescritura de la clase de Joseph Johnson. Esto proporcionará una base muy sólida para la implementación de una costumbre pan vs su tamaño.
package some.package.name;
import some.package.name.JavaScriptObject;
import android.app.Activity;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
//-------------------------------------------------------
// ActivityPanner Class
//
// Convenience class to handle Activity attributes bug.
// Use this class instead of windowSoftInputMode="adjustPan".
//
// To implement, call enable() and pass a reference
// to an Activity which already has its content view set.
// Example:
// setContentView( R.layout.someview );
// ActivityPanner.enable( this );
//-------------------------------------------------------
//
// Notes:
//
// The standard method for handling screen panning
// when the virtual keyboard appears is to set an activity
// attribute in the manifest.
// Example:
// <activity
// ...
// android:windowSoftInputMode="adjustPan"
// ... >
// Unfortunately, this is ignored when using the fullscreen attribute:
// android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
//
//-------------------------------------------------------
public class ActivityPanner {
private View contentView_;
private int priorVisibleHeight_;
public static void enable( Activity activity ) {
new ActivityPanner( activity );
}
private ActivityPanner( Activity activity ) {
FrameLayout content = (FrameLayout)
activity.findViewById( android.R.id.content );
contentView_ = content.getChildAt( 0 );
contentView_.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() { panAsNeeded(); }
});
}
private void panAsNeeded() {
// Get current visible height
int currentVisibleHeight = visibleHeight();
// Determine if visible height changed
if( currentVisibleHeight != priorVisibleHeight_ ) {
// Determine if keyboard visiblity changed
int screenHeight =
contentView_.getRootView().getHeight();
int coveredHeight =
screenHeight - currentVisibleHeight;
if( coveredHeight > (screenHeight/4) ) {
// Keyboard probably just became visible
// Get the current focus elements top & bottom
// using a ratio to convert the values
// to the native scale.
float ratio = (float) screenHeight / viewPortHeight();
int elTop = focusElementTop( ratio );
int elBottom = focusElementBottom( ratio );
// Determine the amount of the focus element covered
// by the keyboard
int elPixelsCovered = elBottom - currentVisibleHeight;
// If any amount is covered
if( elPixelsCovered > 0 ) {
// Pan by the amount of coverage
int panUpPixels = elPixelsCovered;
// Prevent panning so much the top of the element
// becomes hidden
panUpPixels = ( panUpPixels > elTop ?
elTop : panUpPixels );
// Prevent panning more than the keyboard height
// (which produces an empty gap in the screen)
panUpPixels = ( panUpPixels > coveredHeight ?
coveredHeight : panUpPixels );
// Pan up
contentView_.setY( -panUpPixels );
}
}
else {
// Keyboard probably just became hidden
// Reset pan
contentView_.setY( 0 );
}
// Save usabale height for the next comparison
priorVisibleHeight_ = currentVisibleHeight;
}
}
private int visibleHeight() {
Rect r = new Rect();
contentView_.getWindowVisibleDisplayFrame( r );
return r.bottom - r.top;
}
// Customize this as needed...
private int viewPortHeight() { return JavaScriptObject.viewPortHeight(); }
private int focusElementTop( final float ratio ) {
return (int) (ratio * JavaScriptObject.focusElementTop());
}
private int focusElementBottom( final float ratio ) {
return (int) (ratio * JavaScriptObject.focusElementBottom());
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-06 15:58:48
De hecho, la apariencia del teclado no parece afectar al Activity
de ninguna manera, sin importar qué windowSoftInputMode
seleccione en el modo FullScreen
.
Aunque no pude encontrar mucha documentación sobre esta propiedad, creo que el modo FullScreen
fue diseñado para aplicaciones de juegos que no requieren mucho uso del teclado de software. Si la suya es una Actividad que requiere la interacción del usuario a través del teclado de software, reconsidere usar un tema que no sea de pantalla completa. Usted podría apagar la barra de título usando un NoTitleBar
temático. ¿Por qué querrías ocultar la barra de notificaciones?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-26 04:50:25
Simplemente manténgase como android:windowSoftInputMode="adjustResize"
. Debido a que se da para mantener solo uno fuera de "adjustResize"
y "adjustPan"
(El modo de ajuste de ventana se especifica con adjustResize o adjustPan. Es muy recomendable que siempre especifique uno u otro). Puedes encontrarlo aquí:
http://developer.android.com/resources/articles/on-screen-inputs.html
Funciona perfectamente para mí.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-24 02:43:32
Agregue android:fitsSystemWindows="true"
a la maquetación, y esta maquetación cambiará de tamaño.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-20 05:25:32
Desea que la barra inferior se adhiera a la parte inferior de la vista, pero cuando se muestra el teclado, deben moverse hacia arriba para colocarse encima del teclado, ¿verdad?
Puedes probar este fragmento de código:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
...>
<RelativeLayout
android:id="@+id/RelativeLayoutTopBar"
...>
</RelativeLayout>
<LinearLayout
android:id="@+id/LinearLayoutBottomBar"
android:layout_alignParentBottom = true
...>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="390dp"
android:orientation="vertical"
android:layout_above="@+id/LinearLayoutBottomBar"
android:layout_below="@+id/RelativeLayoutTopBar">
<ScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:id="@+id/ScrollViewBackground">
...
</ScrollView>
</LinearLayout>
</RelativeLayout>
El BottomBar se pegará a la parte inferior de la vista y el LinearLayout que contiene el ScrollView tomará lo que queda de la vista después de que se muestren la barra superior/inferior y el teclado. Hazme saber si funciona para ti también.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-20 09:39:45
Gracias José por su respuesta. Sin embargo, en el método possiblyResizeChildOfContent (), la porción
else {
// keyboard probably just became hidden
frameLayoutParams.height = usableHeightSansKeyboard;
}
No estaba funcionando para mí, ya que la parte inferior de la vista se ocultó. Así que tuve que tomar una variable global restoreHeight, y en el constructor, inserté la última línea
restoreHeight = frameLayoutParams.height;
Y luego reemplacé la parte mencionada anteriormente con
else {
// keyboard probably just became hidden
frameLayoutParams.height = restoreHeight;
}
Pero no tengo idea de por qué su código no funcionó para mí. Sería de gran ayuda, si alguien puede arrojar luz sobre este.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-27 09:09:55
Solo estaba usando el modo de pantalla completa para ocultar la barra de estado. Sin embargo, quiero que la aplicación cambie el tamaño cuando se muestra el teclado. Todas las otras soluciones (probablemente debido a la edad de post) eran complicadas o no posibles para mi uso (quiero evitar cambiar el código Java para sack de PhoneGap Build).
En lugar de usar pantalla completa, modifiqué mi configuración para Android para que no sea pantalla completa:
<preference name="fullscreen" value="false" />
Y agregó el cordova-plugin-statusbar
, a través de la línea de comandos:
cordova plugin add cordova-plugin-statusbar
Cuando la aplicación se ha cargado, simplemente llamo a un método en el plugin para ocultarse, como:
if (window.cordova && window.cordova.platformId == 'android' && window.StatusBar)
window.StatusBar.hide();
Esto funciona como un encanto. El único inconveniente real es que la barra de estado se ve rápidamente mientras se carga la aplicación. Para mis necesidades, eso no era un problema.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-25 19:14:42
He probado todas las posibles respuestas de stackOverflow, finalmente resolví después de una semana de búsqueda . He utilizado el diseño de coordenadas y cambié esto con LinearLayout y mi problema está solucionado. No sé si posiblemente el diseño de coordenadas tiene errores o algo que sea mi error.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-26 15:23:18
En mi caso, este problema comenzó a suceder una vez que agregué Crosswalk a mi aplicación Cordova. Mi aplicación no se utiliza en pantalla completa y android:windowSoftInputMode="adjustPan".
Ya tenía el plugin ionic keyboard en la aplicación, por lo que detectar si el teclado estaba arriba o abajo fue fácil gracias a él:
// Listen for events to when the keyboard is opened and closed
window.addEventListener("native.keyboardshow", keyboardUp, false);
window.addEventListener('native.keyboardhide', keyboardDown, false);
function keyboardUp()
{
$('html').addClass('keyboardUp');
}
function keyboardDown()
{
$('html').removeClass('keyboardUp');
}
Probé todas las correcciones anteriores, pero la línea simple que terminó haciéndolo por mí fue este poco de css:
&.keyboardUp {
overflow-y: scroll;
}
Espero que esto te salve los pocos días que pasé en este. :)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-06 22:17:56
Usé Joseph Johnson creado AndroidBug5497Workaround clase pero conseguir espacio negro entre softkeyboard y la vista. Me referí a este enlace Greg Ennis . Después de hacer algunos cambios a lo anterior, este es mi código de trabajo final.
public class SignUpActivity extends Activity {
private RelativeLayout rlRootView; // this is my root layout
private View rootView;
private ViewGroup contentContainer;
private ViewTreeObserver viewTreeObserver;
private ViewTreeObserver.OnGlobalLayoutListener listener;
private Rect contentAreaOfWindowBounds = new Rect();
private FrameLayout.LayoutParams rootViewLayout;
private int usableHeightPrevious = 0;
private View mDecorView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sign_up);
mDecorView = getWindow().getDecorView();
contentContainer =
(ViewGroup) this.findViewById(android.R.id.content);
listener = new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
possiblyResizeChildOfContent();
}
};
rootView = contentContainer.getChildAt(0);
rootViewLayout = (FrameLayout.LayoutParams)
rootView.getLayoutParams();
rlRootView = (RelativeLayout) findViewById(R.id.rlRootView);
rlRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightDiff = rlRootView.getRootView().getHeight() - rlRootView.getHeight();
if (heightDiff > Util.dpToPx(SignUpActivity.this, 200)) {
// if more than 200 dp, it's probably a keyboard...
// Logger.info("Soft Key Board ", "Key board is open");
} else {
Logger.info("Soft Key Board ", "Key board is CLOSED");
hideSystemUI();
}
}
});
}
// This snippet hides the system bars.
protected void hideSystemUI() {
// Set the IMMERSIVE flag.
// Set the content to appear under the system bars so that the
content
// doesn't resize when the system bars hide and show.
mDecorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
@Override
protected void onPause() {
super.onPause();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.removeOnGlobalLayoutListener(listener);
}
}
@Override
protected void onResume() {
super.onResume();
if (viewTreeObserver == null || !viewTreeObserver.isAlive()) {
viewTreeObserver = rootView.getViewTreeObserver();
}
viewTreeObserver.addOnGlobalLayoutListener(listener);
}
@Override
protected void onDestroy() {
super.onDestroy();
rootView = null;
contentContainer = null;
viewTreeObserver = null;
}
private void possiblyResizeChildOfContent() {
contentContainer.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds);
int usableHeightNow = contentAreaOfWindowBounds.height();
if (usableHeightNow != usableHeightPrevious) {
rootViewLayout.height = usableHeightNow;
rootView.layout(contentAreaOfWindowBounds.left,
contentAreaOfWindowBounds.top, contentAreaOfWindowBounds.right, contentAreaOfWindowBounds.bottom);
rootView.requestLayout();
usableHeightPrevious = usableHeightNow;
} else {
this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-29 12:02:51
Probé muchas soluciones, incluidas las de Joseph Johnson y Johan Stuyts, pero como resultado obtuve un espacio en blanco entre el contenido y el teclado en algunos dispositivos (como Lenovo s820) en todos los casos. Así que hice algunos cambios en sus códigos y finalmente conseguí una solución de trabajo.
Mi idea se basa en agregar margen a la parte superior del contenido cuando se muestra el teclado.
contentContainer.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds);
int usableHeightNow = contentAreaOfWindowBounds.height();
if (usableHeightNow != usableHeightPrevious) {
int difference = usableHeightNow - usableHeightPrevious;
if (difference < 0 && difference < -150) {
keyboardShowed = true;
rootViewLayout.topMargin -= difference + 30;
rootViewLayout.bottomMargin += 30;
}
else if (difference < 0 && difference > -150){
rootViewLayout.topMargin -= difference + 30;
}
else if (difference > 0 && difference > 150) {
keyboardShowed = false;
rootViewLayout.topMargin = 0;
rootViewLayout.bottomMargin = 0;
}
rootView.requestLayout();
Log.e("Bug Workaround", "Difference: " + difference);
usableHeightPrevious = usableHeightNow;
}
Como puedes ver, agrego 30 px a la diferencia porque hay un pequeño espacio en blanco entre la parte superior de la pantalla y la zona de contenido con margen. Y no sé de dónde aparece, así que decidí hacer márgenes más pequeños y ahora funciona exactamente como lo necesitaba.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-06 11:27:27
Actualmente estoy usando este enfoque y funciona como un encanto. El truco es que obtenemos altura del teclado de diferentes métodos en 21 arriba y abajo y luego lo usamos como el relleno inferior de nuestra vista raíz en nuestra actividad. Asumí que su diseño no necesita un relleno superior (va debajo de la barra de estado), pero en caso de que lo haga, infórmeme para actualizar mi respuesta.
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RelativeLayout mainLayout = findViewById(R.id.main_layout);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ViewCompat.setOnApplyWindowInsetsListener(mainLayout , new OnApplyWindowInsetsListener() {
@Override
public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) {
v.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
return insets;
}
});
} else {
View decorView = getWindow().getDecorView();
final View contentView = mainLayout;
decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
decorView.getWindowVisibleDisplayFrame(r);
//get screen height and calculate the difference with the useable area from the r
int height = decorView.getContext().getResources().getDisplayMetrics().heightPixels;
int diff = height - r.bottom;
//if it could be a keyboard add the padding to the view
if (diff != 0) {
// if the use-able screen height differs from the total screen height we assume that it shows a keyboard now
//check if the padding is 0 (if yes set the padding for the keyboard)
if (contentView.getPaddingBottom() != diff) {
//set the padding of the contentView for the keyboard
contentView.setPadding(0, 0, 0, diff);
}
} else {
//check if the padding is != 0 (if yes reset the padding)
if (contentView.getPaddingBottom() != 0) {
//reset the padding of the contentView
contentView.setPadding(0, 0, 0, 0);
}
}
}
});
}
}
...
}
No olvide dirigir su vista raíz con un id:
Activity_main.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
Espero que ayude a alguien.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-03 08:31:34
Basado en https://stackoverflow.com/a/19494006/1815624 y el deseo de hacer que suceda...
Idea actualizada
Combinando respuestas de
Código pertinente:
if (heightDifference > (usableHeightSansKeyboard / 4)) {
// keyboard probably just became visible
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
} else {
// keyboard probably just became hidden
if(usableHeightPrevious != 0) {
frameLayoutParams.height = usableHeightSansKeyboard;
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
Fuente completa en https://github.com/CrandellWS/AndroidBug5497Workaround/blob/master/AndroidBug5497Workaround.java
Vieja idea
Cree un valor estático de la altura de los contenedores antes de abrir el teclado
Establezca la altura del contenedor en función de usableHeightSansKeyboard - heightDifference
cuando se abra el teclado y vuelva al valor guardado cuando se cierre
if (heightDifference > (usableHeightSansKeyboard / 4)) {
// keyboard probably just became visible
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
int mStatusHeight = getStatusBarHeight();
frameLayoutParams.topMargin = mStatusHeight;
((MainActivity)activity).setMyMainHeight(usableHeightSansKeyboard - heightDifference);
if(BuildConfig.DEBUG){
Log.v("aBug5497", "keyboard probably just became visible");
}
} else {
// keyboard probably just became hidden
if(usableHeightPrevious != 0) {
frameLayoutParams.height = usableHeightSansKeyboard;
((MainActivity)activity).setMyMainHeight();
}
frameLayoutParams.topMargin = 0;
if(BuildConfig.DEBUG){
Log.v("aBug5497", "keyboard probably just became hidden");
}
}
Métodos en MainActivity
public void setMyMainHeight(final int myMainHeight) {
runOnUiThread(new Runnable() {
@Override
public void run() {
ConstraintLayout.LayoutParams rLparams = (ConstraintLayout.LayoutParams) myContainer.getLayoutParams();
rLparams.height = myMainHeight;
myContainer.setLayoutParams(rLparams);
}
});
}
int mainHeight = 0;
public void setMyMainHeight() {
runOnUiThread(new Runnable() {
@Override
public void run() {
ConstraintLayout.LayoutParams rLparams = (ConstraintLayout.LayoutParams) myContainer.getLayoutParams();
rLparams.height = mainHeight;
myContainer.setLayoutParams(rLparams);
}
});
}
Ejemplo de contenedor XML
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<android.support.constraint.ConstraintLayout
android:id="@+id/my_container"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintHeight_percent=".8">
De manera similar, se pueden agregar márgenes si es necesario...
Otro un ejemplo de esto se puede encontrar en:
Https://github.com/mikepenz/MaterialDrawer/issues/95#issuecomment-80519589
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-05 14:45:15