windowSoftInputMode = “adjustResize” no funciona con la acción translúcida / barra de navegación

Tengo problemas con la barra de navegación / barra de acción translúcida en el nuevo Android KitKat (4.4) y el windowSoftInputMode="adjustResize" .

Cambiando normalmente el InputMode para adjustResize, la aplicación debería redimensionarse cuando se muestre el teclado … ¡pero aquí no lo hará! Si elimino las líneas para el efecto transparente, el cambio de tamaño está funcionando.

Entonces, si el teclado está visible, mi ListView está debajo y no puedo acceder a los últimos elementos. (Solo escondiendo el teclado manualmente)

AndroidManifest.xml

             

values-v19 / styles.xml

    true true   

fragment.xml

      

¿Alguien tiene ideas para arreglar esto?

Te estás perdiendo la siguiente propiedad:

 android:fitsSystemWindows="true" 

en la raíz RelativeLayout del fragmento .xml layout.

Actualizar:

El año pasado hubo una charla interesante de Chris Bane que explica en detalle cómo funciona esto:

https://www.youtube.com/watch?v=_mGDMVRO3iE

Hay un informe de error relacionado aquí . He encontrado una solución alternativa que, a partir de pruebas limitadas, parece ser la solución sin repercusiones. Agregue una implementación personalizada de su ViewGroup raíz (casi siempre estoy usando FrameLayout , así que esto es con lo que he probado) con la siguiente lógica. Luego, use este diseño personalizado en lugar de su diseño raíz, y asegúrese de configurar android:fitsSystemWindows="true" . A continuación, puede llamar a getInsets() cualquier momento después del diseño (por ejemplo, agregar un OnPreDrawListener ) para ajustar el rest de su diseño para tener en cuenta las inserciones del sistema, si lo desea.

 import android.content.Context; import android.graphics.Rect; import android.os.Build; import android.util.AttributeSet; import android.widget.FrameLayout; import org.jetbrains.annotations.NotNull; /** * @author Kevin * Date Created: 3/7/14 * * https://code.google.com/p/android/issues/detail?id=63777 * * When using a translucent status bar on API 19+, the window will not * resize to make room for input methods (ie * {@link android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE} and * {@link android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_PAN} are * ignored). * * To work around this; override {@link #fitSystemWindows(android.graphics.Rect)}, * capture and override the system insets, and then call through to FrameLayout's * implementation. * * For reasons yet unknown, modifying the bottom inset causes this workaround to * fail. Modifying the top, left, and right insets works as expected. */ public final class CustomInsetsFrameLayout extends FrameLayout { private int[] mInsets = new int[4]; public CustomInsetsFrameLayout(Context context) { super(context); } public CustomInsetsFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); } public CustomInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public final int[] getInsets() { return mInsets; } @Override protected final boolean fitSystemWindows(@NotNull Rect insets) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // Intentionally do not modify the bottom inset. For some reason, // if the bottom inset is modified, window resizing stops working. // TODO: Figure out why. mInsets[0] = insets.left; mInsets[1] = insets.top; mInsets[2] = insets.right; insets.left = 0; insets.top = 0; insets.right = 0; } return super.fitSystemWindows(insets); } } 

Debido a que fitSystemWindow s está en desuso, consulte la respuesta a continuación para completar la solución.

La respuesta de @kcoppock es realmente útil, pero fitSystemWindows quedó en desuso en el nivel de API 20

Por lo tanto, desde la API 20 (KITKAT_WATCH) debes anular enApplyWindowInsets

 @Override public final WindowInsets onApplyWindowInsets(WindowInsets insets) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { return super.onApplyWindowInsets(insets.replaceSystemWindowInsets(0, 0, 0, insets.getSystemWindowInsetBottom())); } else { return insets; } } 

Esto funcionó para mí para tener una barra de estado translúcida y adjustResize en fragmento:

  1. Haga un RelativeLayout personalizado como lo dicen @ Victor91 y @kcoppock.

  2. Use CustomRelativeLayout como diseño principal para su fragmento.

  3. Declarar el tema con android: windowTranslucentStatus = true

  4. La actividad del contenedor debe declararse en Manifest con android: windowSoftInputMode = “adjustResize” y usar el tema declarado

  5. Utilice fitsSystemWindows en el diseño de raíz de fragmento.

     public class CustomRelativeLayout extends RelativeLayout { private int[] mInsets = new int[4]; public CustomRelativeLayout(Context context) { super(context); } public CustomRelativeLayout(Context context, AttributeSet attrs) { super(context, attrs); } public CustomRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public CustomRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public final WindowInsets onApplyWindowInsets(WindowInsets insets) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { mInsets[0] = insets.getSystemWindowInsetLeft(); mInsets[1] = insets.getSystemWindowInsetTop(); mInsets[2] = insets.getSystemWindowInsetRight(); return super.onApplyWindowInsets(insets.replaceSystemWindowInsets(0, 0, 0, insets.getSystemWindowInsetBottom())); } else { return insets; } } } 

Luego en xml,

   

Tuve el mismo problema, Mi actividad tenía una Vista de desplazamiento como vista raíz y con la barra de estado translúcida activada no cambiaba de tamaño correctamente cuando se mostraba el teclado … y consecuentemente la pantalla no se desplazaba ocultando las vistas de entrada.

Solución: moví todo (lógica de diseño y actividad) dentro de un nuevo Fragmento. Luego cambió la Actividad para incluir solo este Fragmento. ¡Ahora todo funciona como se espera!

Este es el diseño de la actividad:

   

Basado en la solución alternativa de Joseph Johnson en Android Cómo ajustar el diseño en el modo de pantalla completa cuando el teclado es visible

llámalo onCreate() después de setContentView() en tu actividad.

AndroidBug5497Workaround.assistActivity(this);

un poco diferente del return (r.bottom - r.top); reemplazo original return (r.bottom - r.top); con return r.bottom; en computeUsableHeight()

por alguna razón, debo establecer mi atributo de actividad fitsSystemWindows en false .

esta solución me salvó. me funciona bien la esperanza puede ayudarte

la clase de implementación es:

 public class AndroidBug5497Workaround { // 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 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; } } 

Si desea personalizar las inserciones y tiene como objective el nivel de API> = 21, puede hacerlo sin tener que crear un grupo de vista personalizado. Con solo establecer el ajuste de fitsSystemWindows se aplicará a su vista de contenedor de forma predeterminada, lo que puede no desear.

Las verificaciones de versión están integradas en este método y solo los dispositivos> = 21 ejecutarán el código dentro de la lambda. Ejemplo de Kotlin:

 ViewCompat.setOnApplyWindowInsetsListener(container) { view, insets -> insets.replaceSystemWindowInsets(0, 0, 0, insets.systemWindowInsetBottom).apply { ViewCompat.onApplyWindowInsets(view, this) } } 

Asegúrate de que tu diseño aún establezca el fitsSystemWindows , de lo contrario no se fitsSystemWindows al oyente de las inserciones de ventana.

  

Estas fonts son útiles:

https://medium.com/google-developers/why-would-i-want-to-fitssystemwindows-4e26d9ce1eec https://medium.com/@azizbekian/windowinsets-24e241d4afb9

AndroidBug5497Workaround.java se ocupa de la pérdida de memoria. necesita un código debajo

 getViewTreeObserver().removeOnGlobalLayoutListener(listener); 

Mi ejemplo usando RxJava que llama automáticamente removeOnGlobalLayoutListener () cuando está en pausa () en el ciclo de vida de la actividad

 public class MyActivity extends RxAppCompatActivity { // ... protected void onStart(){ super.onStart(); TRSoftKeyboardVisibility .changes(this) // activity .compose(this.bindUntilEvent(ActivityEvent.PAUSE)) .subscribe(keyboardEvent -> { FrameLayout content = (FrameLayout) findViewById(android.R.id.content); View firstChildView = content.getChildAt(0); firstChildView.getLayoutParams().height = keyboardEvent.viewHeight(); firstChildView.requestLayout(); // keyboardEvent.isVisible = keyboard visible or not // keyboardEvent.keyboardHeight = keyboard height // keyboardEvent.viewHeight = fullWindowHeight - keyboardHeight }); //... } package commonlib.rxjava.keyboard; import android.app.Activity; import android.view.View; import android.widget.FrameLayout; import kr.ohlab.android.util.Assert; import rx.Observable; public class TRSoftKeyboardVisibility { public static Observable changes(Activity activity) { Assert.notNull(activity, "activity == null"); FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content); View childOfContent = content.getChildAt(0); return Observable.create( new TRSoftKeyboardVisibilityEventOnSubscribe(childOfContent)); } public static final class ChangeEvent { private final int keyboardHeight; private final boolean visible; private final int viewHeight; public static ChangeEvent create(boolean visible, int keyboardHeight, int windowDisplayHeight) { return new ChangeEvent(visible, keyboardHeight, windowDisplayHeight); } private ChangeEvent(boolean visible, int keyboardHeight, int viewHeight) { this.keyboardHeight = keyboardHeight; this.visible = visible; this.viewHeight = viewHeight; } public int keyboardHeight() { return keyboardHeight; } public boolean isVisible() { return this.visible; } public int viewHeight() { return viewHeight; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof ChangeEvent)) return false; ChangeEvent that = (ChangeEvent) o; if (keyboardHeight != that.keyboardHeight) return false; if (visible != that.visible) return false; return viewHeight == that.viewHeight; } @Override public int hashCode() { int result = keyboardHeight; result = 31 * result + (visible ? 1 : 0); result = 31 * result + viewHeight; return result; } @Override public String toString() { return "ChangeEvent{" + "keyboardHeight=" + keyboardHeight + ", visible=" + visible + ", viewHeight=" + viewHeight + '}'; } } } package commonlib.rxjava.keyboard; import android.graphics.Rect; import android.view.View; import android.view.ViewTreeObserver; import kr.ohlab.android.util.Assert; import rx.Observable; import rx.Subscriber; import rx.android.MainThreadSubscription; import timber.log.Timber; public class TRSoftKeyboardVisibilityEventOnSubscribe implements Observable.OnSubscribe { private final View mTopView; private int mLastVisibleDecorViewHeight; private final Rect mWindowVisibleDisplayFrame = new Rect(); public TRSoftKeyboardVisibilityEventOnSubscribe(View topView) { mTopView = topView; } private int computeWindowFrameHeight() { mTopView.getWindowVisibleDisplayFrame(mWindowVisibleDisplayFrame); return (mWindowVisibleDisplayFrame.bottom - mWindowVisibleDisplayFrame.top); } private TRSoftKeyboardVisibility.ChangeEvent checkKeyboardVisibility() { int windowFrameHeightNow = computeWindowFrameHeight(); TRSoftKeyboardVisibility.ChangeEvent event = null; if (windowFrameHeightNow != mLastVisibleDecorViewHeight) { int mTopViewHeight = mTopView.getHeight(); int heightDiff = mTopViewHeight - windowFrameHeightNow; Timber.e("XXX heightDiff=" + heightDiff); if (heightDiff > (mTopViewHeight / 4)) { event = TRSoftKeyboardVisibility.ChangeEvent.create(true, heightDiff, windowFrameHeightNow); } else { event = TRSoftKeyboardVisibility.ChangeEvent.create(false, 0, windowFrameHeightNow); } mLastVisibleDecorViewHeight = windowFrameHeightNow; return event; } return null; } public void call(final Subscriber subscriber) { Assert.checkUiThread(); final ViewTreeObserver.OnGlobalLayoutListener listener = new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { TRSoftKeyboardVisibility.ChangeEvent event = checkKeyboardVisibility(); if( event == null) return; if (!subscriber.isUnsubscribed()) { subscriber.onNext(event); } } }; mTopView.getViewTreeObserver().addOnGlobalLayoutListener(listener); subscriber.add(new MainThreadSubscription() { @Override protected void onUnsubscribe() { mTopView.getViewTreeObserver().removeOnGlobalLayoutListener(listener); } }); } } 

Tuve un problema

Establecí windowDrawsSystemBarBackgrounds en ‘true’ y mi aplicación debería mostrarse debajo de la barra de estado.

Es mi tema de actividad.

 false true true @android:color/transparent 

y recibí ayuda del blog de jianshu . puedes leer el código pero el texto me gusta. Agregué algunos códigos más.

 public final class ZeroInsetsFrameLayout extends FrameLayout { private int[] mInsets = new int[4]; public ZeroInsetsFrameLayout(Context context) { super(context); } public ZeroInsetsFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); } public ZeroInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public final int[] getInsets() { return mInsets; } @Override public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { outLocalInsets.left = 0; outLocalInsets.top = 0; outLocalInsets.right = 0; return super.computeSystemWindowInsets(in, outLocalInsets); } @Override protected final boolean fitSystemWindows(@NonNull Rect insets) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // Intentionally do not modify the bottom inset. For some reason, // if the bottom inset is modified, window resizing stops working. // TODO: Figure out why. mInsets[0] = insets.left; mInsets[1] = insets.top; mInsets[2] = insets.right; insets.left = 0; insets.top = 0; insets.right = 0; } return super.fitSystemWindows(insets); } } 

Este es mi diseño de fragmento.

    

Quiero que te sea útil. ¡buena suerte!

La mejor práctica permite al usuario desplazarse por el contenido cuando se muestra el teclado. Entonces, para agregar esta funcionalidad necesita poner su diseño de raíz dentro de ScrollView y usar el método de actividad windowSoftInputMode="adjustResize" .

Pero si desea utilizar esta funcionalidad con el true en el contenido de Android 5, no podrá desplazarse y se superpondrá con el teclado.

Para resolver este problema, compruebe esta respuesta

No debería funcionar con la barra de estado translúcida; esa configuración fuerza a la ventana al modo de pantalla completa, que no funciona con adjustResize.

Puede usar adjustPan o usar las propiedades de fitsSystemWindows. Sugeriría leer acerca de la característica, sin embargo, tiene efectos secundarios significativos:

https://medium.com/google-developers/why-would-i-want-to-fitssystemwindows-4e26d9ce1eec

  • Después de haber investigado en todos los foros. Estas formas no pueden ayudar a encontrar un punto. Suerte cuando traté de hacerlo de esta manera. Me ayuda a resolver el problema

XML

    

Actividad

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView("Your Activity"); setAdjustScreen(); } 

Func Creado

 protected void setAdjustScreen(){ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); /*android:windowSoftInputMode="adjustPan|adjustResize"*/ } 

Finalmente, agregando algunas líneas a su mainifest

   

Yo tuve el mismo problema. Lo he resuelto usando el coordinatorlayout

activity.main.xml

        

content_main2.xml

       

MainActivity.java

ahora agregue esta línea linearLayoutManager.setStackFromEnd (true);

  LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); linearLayoutManager.setStackFromEnd(true); recyclerView.setLayoutManager(linearLayoutManager); Adapter adapter1=new Adapter(arrayList); recyclerView.setAdapter(adapter1); 
    Intereting Posts