fitsSystemWindows effect gone for fragments added via FragmentTransaction
When you use <fragment>
, the layout returned in your Fragment's onCreateView
is directly attached in place of the <fragment>
tag (you'll never actually see a <fragment>
tag if you look at your View hierarchy.
Therefore in the <fragment>
case, you have
DrawerLayout
CoordinatorLayout
AppBarLayout
...
NavigationView
Similar to how cheesesquare works. This works because, as explained in this blog post, DrawerLayout
and CoordinatorLayout
both have different rules on how fitsSystemWindows
applies to them - they both use it to inset their child Views, but also call dispatchApplyWindowInsets() on each child, allowing them access to the fitsSystemWindows="true"
property.
This is a difference from the default behavior with layouts such as FrameLayout
where when you use fitsSystemWindows="true"
is consumes all insets, blindly applying padding without informing any child views (that's the 'depth first' part of the blog post).
So when you replace the <fragment>
tag with a FrameLayout
and FragmentTransactions, your view hierarchy becomes:
DrawerLayout
FrameLayout
CoordinatorLayout
AppBarLayout
...
NavigationView
as the Fragment's view is inserted into the FrameLayout
. That View doesn't know anything about passing fitsSystemWindows
to child views, so your CoordinatorLayout
never gets to see that flag or do its custom behavior.
Fixing the problem is actually fairly simple: replace your FrameLayout
with another CoordinatorLayout
. This ensures the fitsSystemWindows="true"
gets passed onto the newly inflated CoordinatorLayout
from the Fragment.
Alternate and equally valid solutions would be to make a custom subclass of FrameLayout
and override onApplyWindowInsets() to dispatch to each child (in your case just the one) or use the ViewCompat.setOnApplyWindowInsetsListener() method to intercept the call in code and dispatch from there (no subclass required). Less code is usually the easiest to maintain, so I wouldn't necessarily recommend going these routes over the CoordinatorLayout
solution unless you feel strongly about it.
Android fitsSystemWindows not working when replacing fragments
Your FrameLayout
is not aware of window inset sizes, because it's parent - LinearLayout
hasn't dispatched it any. As a workaround, you can subclass LinearLayout
and pass insets to children on your own:
@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
int childCount = getChildCount();
for (int index = 0; index < childCount; index++)
getChildAt(index).dispatchApplyWindowInsets(insets); // let children know about WindowInsets
return insets;
}
You can have a look to my this answer, which will explain detailed how this works, and also how to use ViewCompat.setOnApplyWindowInsetsListener
API.
Change toolbar from fragment
It's been a wild ride, but I finally found a solution. For the issue number 1, this is due to the way Android manages the fitsSystemWindows
property propagation. For this to work correctly, I made a few changes to my layouts. I created a custom FitSystemWindowLinearLayout
, which is simply a class extending the standard LinearLayout
and overriding onApplyWindowInsets
like this:
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
int childCount = getChildCount();
for (int index = 0; index < childCount; ++index) {
getChildAt(index).dispatchApplyWindowInsets(insets);
}
return insets;
}
My main activity now looks like this:
+-- CoordinatorLayout, fitsSystemWindows=false
+-- FitSystemWindowLinearLayout, fitsSystemWindows="false"
+-- Toolbar
+-- NavHostFragment, fitsSystemWindows="false"
+-- BottomNavigationView, fitsSystemWindows="false"
For the second issue, namely the transition being ugly, I mitigated that by adding a shared element to the transition.
All in all, I think it's easier to use a new activity for this kind of things, the NavigationUI falls a bit short for now.
Here are some resources that helped me:
- https://medium.com/androiddevelopers/why-would-i-want-to-fitssystemwindows-4e26d9ce1eec
- Android fitsSystemWindows not working when replacing fragments
- Collapsing Toolbar problems with Status Bar and Bottom Bar. Fitssystemwindows="true" not working
- fitsSystemWindows effect gone for fragments added via FragmentTransaction
- https://www.reddit.com/r/androiddev/comments/aryxvu/fitssystemwindows_misbehaves_with_navigation/
-https://medium.com/androiddevelopers/why-would-i-want-to-fitssystemwindows-4e26d9ce1eec
Android 4.4 — Translucent status/navigation bars — fitsSystemWindows/clipToPadding don't work through fragment transactions
I solved the issue by using the library I use the set the color of my translucent status bar.
The SystemBarConfig
class of SystemBarTint (as seen here https://github.com/jgilfelt/SystemBarTint#systembarconfig) lets you get insets which I set as the padding to the list in every fragment, along with the use of clipToPadding="false"
on the list.
I have details of what I've done on this post: http://mindofaandroiddev.wordpress.com/2013/12/28/making-the-status-bar-and-navigation-bar-transparent-with-a-listview-on-android-4-4-kitkat/
How to correctly implement view content behind statusbar when using fragments
Ok the problem was the content_main.xml it's always replaced so I thought it wasn't necessary to have the android:fitsSystemWindows attribute but i was wrong, adding android:fitsSystemWindows="true" solved the problem.
snippet content_main:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
android:id="@+id/fragment_container"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"/>
Important: if like me after that you find a bug in viewPager when coordinatorLayout has android:fitsSystemWindows="true" take a look here: CoordinatorLayout status bar padding disappears from ViewPager 2nd page
Related Topics
Listen to Own Application Uninstall Event on Android
How to Disable Status Bar Click and Pull Down in Android
Android Studio Fails to Build New Project, Timed Out While Wating for Slave Aapt Process
Using Onsaveinstancestate with Fragments in Backstack
How to Open My Existing Eclipse Projects in Android Studio
Programmatically Add View One Below Other in Relative Layout
Bring Application to Front After User Clicks on Home Button
Continually Running Background Service
Highlight Listview Selected Row
How to Create a Database in Android
How to Order My SQLite Database in Descending Order, for an Android App
How to Set Text to View from Drawer Header Layout in Navigation Drawer Without Inflating View
Send Post Request with Params Using Retrofit
Android How to Runonuithread in Other Class
How to Add an Image File into JSON Object