fitsystemwindows - android android fitssystemwindows
Android 4.4-Barras de navegación/estado translúcidas-fitsSystemWindows/clipToPadding no funcionan a través de transacciones fragmentadas (8)
Cuando se utilizan las barras de estado y navegación translúcidas de las nuevas API de Android 4.4 KitKat, la configuración de fitsSystemWindows="true"
y clipToPadding="false"
en un ListView
funciona inicialmente. fitsSystemWindows="true"
mantiene la lista debajo de la barra de acción y arriba de la barra de navegación, clipToPadding="false"
permite que la lista se desplace debajo de la barra de navegación transparente y hace que el último elemento de la lista se desplace hacia arriba lo suficiente para pasar la navegación bar.
Sin embargo, cuando reemplaza el contenido con otro Fragment
través de un FragmentTransaction
el efecto de fitsSystemWindows
desaparece y el fragmento se fitsSystemWindows
debajo de la barra de acción y la barra de navegación.
Tengo una base de código de código fuente de demostración aquí junto con un APK descargable como ejemplo: https://github.com/afollestad/kitkat-transparency-demo . Para ver de qué estoy hablando, abra la aplicación de demostración desde un dispositivo que ejecuta KitKat, toque un elemento de la lista (que abrirá otra actividad) y toque un elemento en la nueva actividad que se abre. El fragmento que reemplaza el contenido va debajo de la barra de acción y clipToPadding no funciona correctamente (la barra de navegación cubre el último elemento de la lista cuando se desplaza completamente hacia abajo).
¿Algunas ideas? ¿Alguna aclaración necesaria? Publiqué las capturas de pantalla de antes y después de mi aplicación personal desarrollada para mi empleador.
Ayer luché con el mismo problema. Después de pensar mucho, encontré una solución elegante para este problema.
Primero, vi el método requestFitSystemWindows()
en ViewParent
e intenté llamarlo en onActivityCreated()
del fragmento (después de que el fragmento se adjunta a la jerarquía de vistas), pero lamentablemente no tuvo ningún efecto. Me gustaría ver un ejemplo concreto de cómo usar ese método.
Luego encontré una solución ordenada: creé un FitsSystemWindowsFrameLayout
personalizado que utilizo como contenedor de fragmentos en mis diseños, como reemplazo para un FrameLayout
clásico. Lo que hace es memorizar las inserciones de ventana cuando el sistema llama a fitSystemWindows()
, luego propaga la llamada nuevamente a su disposición secundaria (la disposición del fragmento) tan pronto como se agrega / adjunta el fragmento.
Aquí está el código completo:
public class FitsSystemWindowsFrameLayout extends FrameLayout {
private Rect windowInsets = new Rect();
private Rect tempInsets = new Rect();
public FitsSystemWindowsFrameLayout(Context context) {
super(context);
}
public FitsSystemWindowsFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FitsSystemWindowsFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected boolean fitSystemWindows(Rect insets) {
windowInsets.set(insets);
super.fitSystemWindows(insets);
return false;
}
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
super.addView(child, index, params);
tempInsets.set(windowInsets);
super.fitSystemWindows(tempInsets);
}
}
Creo que esto es mucho más simple y robusto que los hacks que intentan determinar los tamaños de los elementos de la interfaz de usuario mediante el acceso a propiedades ocultas del sistema que pueden variar con el tiempo y luego aplicar el relleno manualmente a los elementos.
Bien, esto es increíblemente raro. Hace poco me encontré con este mismo problema, excepto que el mío involucra un teclado suave . Inicialmente funciona, pero si agrego una transacción de fragmento, el android:fitsSystemWindows="true"
ya no funciona. Intenté toda la solución aquí, ninguno de ellos funcionó para mí.
Aquí está mi problema:
En lugar de cambiar el tamaño de mi vista, aumenta mi vista y ese es el problema.
Sin embargo, tuve suerte y tropecé accidentalmente con una respuesta que me funcionó.
Asi que aqui esta:
En primer lugar, el tema de mi aplicación es: Theme.AppCompat.Light.NoActionBar (si eso es relevante, tal vez lo sea, Android es raro).
Maurycy señaló algo muy interesante aquí, así que quería probar si lo que decía era verdad o no. Lo que dijo también era cierto en mi caso ... A MENOS QUE agregue este atributo a su actividad en el manifiesto de Android de su aplicación:
Una vez que agregues:
android:windowSoftInputMode="adjustResize"
a su actividad, android:fitsSystemWindows="true"
ya no se ignora después de la transacción del fragmento!
Sin embargo, prefiero que llames a android:fitsSystemWindows="true"
NO en el diseño raíz de tu Fragmento. Uno de los lugares más grandes donde ocurrirá este problema es dónde tiene EditText o ListView. Si está atrapado en este apuro como lo hice yo, establezca android:fitsSystemWindows="true"
en el elemento secundario del diseño raíz como este:
SÍ, esta solución funciona en todos los dispositivos Lollipop y pre-lollipop.
Y aquí está la prueba:
Vuelve a dimensionar en lugar de empujar el diseño hacia arriba. Así que espero haber ayudado a alguien que está en el mismo barco que yo.
¡Muchas gracias a todos!
Combinado con la respuesta de @BladeCoder, he creado la clase FittedFrameLayout que hace dos cosas:
- no agrega relleno para sí mismo
escanea a través de todas las vistas dentro de su contenedor y agrega relleno para ellos, pero se detiene en la capa más baja (si se encuentra el indicador de windowssystemssystems no escaneará al niño más profundo, pero aún en la misma profundidad o por debajo).
public class FittedFrameLayout extends FrameLayout { private Rect insets = new Rect(); public FittedFrameLayout(Context context) { super(context); } public FittedFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); } public FittedFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public FittedFrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } protected void setChildPadding(View view, Rect insets){ if(!(view instanceof ViewGroup)) return; ViewGroup parent = (ViewGroup) view; if (parent instanceof FittedFrameLayout) ((FittedFrameLayout)parent).fitSystemWindows(insets); else{ if( ViewCompat.getFitsSystemWindows(parent)) parent.setPadding(insets.left,insets.top,insets.right,insets.bottom); else{ for (int i = 0, z = parent.getChildCount(); i < z; i++) setChildPadding(parent.getChildAt(i), insets); } } } @Override protected boolean fitSystemWindows(Rect insets) { this.insets = insets; for (int i = 0, z = getChildCount(); i < z; i++) setChildPadding(getChildAt(i), insets); return true; } @Override public void addView(View child, int index, ViewGroup.LayoutParams params) { super.addView(child, index, params); setChildPadding(child, insets); } }
He resuelto esta pregunta en 4.4
if(test){
Log.d(TAG, "fit true ");
relativeLayout.setFitsSystemWindows(true);
relativeLayout.requestFitSystemWindows();
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}else {
Log.d(TAG, "fit false");
relativeLayout.setFitsSystemWindows(false);
relativeLayout.requestFitSystemWindows();
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
Me encontré con el mismo problema. Cuando sustituyo Fragmento. El ''fitsSystemWindows'' no funciona.
Arreglado por código agregar a tu fragmento
@Override
public void onViewCreated(final View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
AndroidUtil.runOnUIThread(new Runnable() {
@Override
public void run() {
((ViewGroup) getView().getParent()).setFitsSystemWindows(true);
}
});
}
Resolví el problema usando la biblioteca, uso el color de mi barra de estado translúcida.
La clase SystemBarConfig
de SystemBarTint (como se ve aquí https://github.com/jgilfelt/SystemBarTint#systembarconfig ) le permite obtener inserciones que puse como relleno en la lista en cada fragmento, junto con el uso de clipToPadding="false"
en la lista.
Tengo detalles de lo que he hecho en este post: http://mindofaandroiddev.wordpress.com/2013/12/28/making-the-status-bar-and-navigation-bar-transparent-with-a-listview-on-android-4-4-kitkat/
También he estado luchando bastante con esto. He visto todas las respuestas aquí. Desafortunadamente ninguno de ellos estaba solucionando mi problema el 100% del tiempo. SystemBarConfig no funciona siempre porque no detecta la barra en algunos dispositivos. Eché un vistazo al código fuente y encontré dónde se guardan las inserciones dentro de la ventana.
Rect insets = new Rect();
Window window = getActivity().getWindow();
try {
Class clazz = Class.forName("com.android.internal.policy.impl.PhoneWindow");
Field field = clazz.getDeclaredField("mDecor");
field.setAccessible(true);
Object decorView = field.get(window);
Field insetsField = decorView.getClass().getDeclaredField("mFrameOffsets");
insetsField.setAccessible(true);
insets = (Rect) insetsField.get(decorView);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
Esta es la forma de conseguirlos. Al parecer, en Android L habrá un buen método para obtener esas inserciones, pero mientras tanto, esta podría ser una buena solución.
Un cara a cara para algunas personas que se encuentran con este problema
Una pieza clave de información con el método fitSystemWindows que realiza gran parte del trabajo:
El recorrido de esta función en la jerarquía es primero en profundidad. El mismo objeto de inserciones de contenido se propaga a través de la jerarquía, por lo que los cambios que se realicen en él serán vistos por todas las siguientes vistas (incluidas las que se encuentran arriba en la jerarquía, ya que este es un recorrido primero en profundidad) La primera vista que devuelve true abortará todo el recorrido.
Por lo tanto, si tiene otros fragmentos con vistas de contenido que tienen ajustados a SystemWindows configurados como verdaderos, el indicador será potencialmente ignorado. Consideraría que su contenedor de fragmentos contenga la bandera de fitSystemWindows si es posible. De lo contrario, añadir manualmente el relleno.