with tutorial studio por iniciar inicializar fragments defecto android android-layout android-fragments

tutorial - navigation drawer android



El efecto de fitSystemWindows se ha ido para fragmentos agregados a través de FragmentTransaction (6)

Tengo una actividad con el cajón de navegación y el fragmento de sangrado completo (con una imagen en la parte superior que debe aparecer detrás de la barra del sistema translúcido en Lollipop). Si bien tenía una solución provisional en la que el Fragmento se inflaba simplemente con la etiqueta <fragment> en el XML de Activity, se veía bien.

Luego tuve que reemplazar <fragment> con <FrameLayout> y realizar transacciones de fragmentos, y ahora el fragmento ya no aparece detrás de la barra del sistema, a pesar de que fitsSystemWindows está establecido en true en toda la jerarquía requerida.

Creo que podría haber alguna diferencia entre cómo se infla <fragment> dentro del diseño de Activity versus por sí solo. Busqué en Google y encontré algunas soluciones para KitKat, pero ninguna de ellas funcionó para mí (Lollipop).

activity.xml

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/drawer_layout" android:layout_height="match_parent" android:layout_width="match_parent" android:fitsSystemWindows="true"> <FrameLayout android:id="@+id/fragment_host" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> </FrameLayout> <android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_height="match_parent" android:layout_width="wrap_content" android:layout_gravity="start" android:fitsSystemWindows="true"/> </android.support.v4.widget.DrawerLayout>

fragment.xml

<android.support.design.widget.CoordinatorLayout 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:fitsSystemWindows="true"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="224dp" android:fitsSystemWindows="true" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> ...

Funcionó cuando activity.xml era de esta manera:

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/drawer_layout" android:layout_height="match_parent" android:layout_width="match_parent" android:fitsSystemWindows="true"> <fragment xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/fragment" android:name="com.actinarium.random.ui.home.HomeCardsFragment" tools:layout="@layout/fragment_home" android:layout_width="match_parent" android:layout_height="match_parent"/> <android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_height="match_parent" android:layout_width="wrap_content" android:layout_gravity="start" android:fitsSystemWindows="true"/> </android.support.v4.widget.DrawerLayout>


Bien, después de que varias personas fitsSystemWindows que el sistema fitsSystemWindows funciona de manera diferente, y que no debería usarse en cada vista de la jerarquía, seguí experimentando y eliminando la propiedad de diferentes vistas.

fitsSystemWindows estado esperado después de eliminar fitsSystemWindows de cada nodo en activity.xml = /


Creé este último año para resolver este problema: https://gist.github.com/cbeyls/ab6903e103475bd4d51b

Editar: asegúrese de comprender lo que se ajusta primero a SystemSindows. Cuando lo configura en una Vista, básicamente significa: "coloque esta Vista y todos sus elementos secundarios debajo de la barra de estado y encima de la barra de navegación". No tiene sentido establecer este atributo en el contenedor superior.


Cuando usa <fragment> , el diseño devuelto en onCreateView su Fragment se adjunta directamente en lugar de la etiqueta <fragment> (en realidad nunca verá una etiqueta <fragment> si mira su jerarquía de Vista.

Por lo tanto, en el caso <fragment> , tienes

DrawerLayout CoordinatorLayout AppBarLayout ... NavigationView

Similar a cómo funciona cheesesquare . Esto funciona porque, como se explica en esta publicación de blog , DrawerLayout y CoordinatorLayout tienen reglas diferentes sobre cómo se aplica a fitsSystemWindows : ambos lo usan para insertar sus Vistas secundarias, pero también llaman a dispatchApplyWindowInsets() en cada elemento secundario, lo que les permite acceder a fitsSystemWindows="true" propiedad fitsSystemWindows="true" .

Esta es una diferencia con respecto al comportamiento predeterminado con diseños como FrameLayout donde cuando se utiliza fitsSystemWindows="true" se consumen todas las inserciones, aplicando a ciegas el relleno sin informar las vistas secundarias (esa es la parte ''profunda primero'' de la publicación del blog).

Entonces, cuando reemplaza la etiqueta <fragment> con FrameLayout y FragmentTransactions, su jerarquía de vistas se convierte en:

DrawerLayout FrameLayout CoordinatorLayout AppBarLayout ... NavigationView

a medida que la vista del Fragmento se inserta en FrameLayout . Esa vista no sabe nada sobre cómo pasar los fitsSystemWindows de fitsSystemWindows a las vistas secundarias, por lo que su CoordinatorLayout nunca puede ver esa bandera o hacer su comportamiento personalizado.

En realidad, solucionar el problema es bastante simple: reemplace su FrameLayout con otro CoordinatorLayout . Esto asegura que el fitsSystemWindows="true" pase al CoordinatorLayout recién inflado desde el Fragmento.

Las soluciones alternativas e igualmente válidas serían hacer una subclase personalizada de FrameLayout y anular onApplyWindowInsets() para enviar a cada hijo (en su caso solo el uno) o usar el método ViewCompat.setOnApplyWindowInsetsListener() para interceptar la llamada en código y despachar desde allí (no se requiere subclase). Por lo general, es menos fácil mantener menos código, por lo que no recomendaría necesariamente seguir estas rutas a través de la solución CoordinatorLayout menos que se sienta muy convencido al respecto.


El otro problema horrendo con el envío de inserciones de ventana es que la primera vista que consume inserciones de ventana en una búsqueda profunda primero evita que todas las demás vistas en la jerarquía vean inserciones de ventana.

El siguiente fragmento de código permite que más de un hijo maneje inserciones de ventanas. Extremadamente útil si está intentando aplicar inserciones de ventanas a decoraciones fuera de una NavigationView (o CoordinatorLayout). Anular en el ViewGroup de su elección.

@Override public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { if (!insets.isConsumed()) { // each child gets a fresh set of window insets // to consume. final int count = getChildCount(); for (int i = 0; i < count; i++) { WindowInsets freshInsets = new WindowInsets(insets); getChildAt(i).dispatchApplyWindowInsets(freshInsets); } } return insets; // and we don''t. }

También útil:

@Override public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { return insets.consume(); // consume without adding padding! }

lo que permite que las vistas ordinarias simples que son elementos secundarios de esta vista se distribuyan sin ventanas.


Mi problema era similar al tuyo: tengo una barra de navegación inferior que está reemplazando los fragmentos de contenido. Ahora algunos de los fragmentos quieren dibujar sobre la barra de estado (con CoordinatorLayout , AppBarLayout ), otros no (con ConstraintLayout , Toolbar ).

ConstraintLayout FrameLayout [the ViewGroup of your choice] BottomNavigationView

La sugerencia de ianhanniballake para agregar otra capa CoordinatorLayout no es lo que quiero, así que creé un FrameLayout personalizado que maneja las inserciones (como sugirió), y después de un tiempo encontré esta solución que realmente no es mucho código:

activity_main.xml

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/content" android:layout_width="match_parent" android:layout_height="match_parent"> <com.example.app.WindowInsetsFrameLayout android:id="@+id/fragment_container" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintBottom_toTopOf="@+id/bottom_navigation" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <BottomNavigationView android:id="@+id/bottom_navigation" android:layout_width="0dp" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> </android.support.constraint.ConstraintLayout>

WindowInsetsFrameLayout.java

/** * FrameLayout which takes care of applying the window insets to child views. */ public class WindowInsetsFrameLayout extends FrameLayout { public WindowInsetsFrameLayout(Context context) { this(context, null); } public WindowInsetsFrameLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public WindowInsetsFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // Look for replaced fragments and apply the insets again. setOnHierarchyChangeListener(new OnHierarchyChangeListener() { @Override public void onChildViewAdded(View parent, View child) { requestApplyInsets(); } @Override public void onChildViewRemoved(View parent, View child) { } }); } }


Otro enfoque escrito en Kotlin,

El problema:

El FrameLayout que está utilizando no propaga fitsSystemWindows="true" a sus hijos:

<FrameLayout android:id="@+id/fragment_host" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" />

Una solución:

Extienda la clase FrameLayout y anule la función onApplyWindowInsets() para propagar las inserciones de ventana a los fragmentos adjuntos:

@TargetApi(Build.VERSION_CODES.LOLLIPOP) class BetterFrameLayout : FrameLayout { constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet) : super(context, attrs) constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) override fun onApplyWindowInsets(windowInsets: WindowInsets): WindowInsets { childCount.let { // propagates window insets to children''s for (index in 0 until it) { getChildAt(index).dispatchApplyWindowInsets(windowInsets) } } return windowInsets } }

Utilice este diseño como un contenedor de fragmentos en lugar del FrameLayout estándar:

<com.foo.bar.BetterFrameLayout android:id="@+id/fragment_host" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" />

Extra:

Si desea saber más acerca de este pago, haga clic en la publicación del blog de Chris Banes Convertirse en un instalador de ventanas maestro .