To be able to make the drawer layout go under the status bar, I've needed to set its color to transparent and set SystemUIVisibility
to fullscreen. When starting Context Action Mode the status bar becomes black.
This can be "solved" by setting the color of the status bar in the OnCreateActionMode
and making it transparent again in OnDestroyActionMode
(although you can still see the black bar for a moment).
The real problem appears when I'm in Contextual Action Mode and I navigate to another fragment, finishing the contextual mode before navigating. This makes the black view appear over the fragment's layout and it can't be removed.
You can see an image of this behavior:
I'm using Xamarin Android, but the implementation in java should be fairly similar. The drawer layout and main content are all created programmatically:
To set the status bar:
if (Build.VERSION.SdkInt > BuildVersionCodes.Lollipop)
{
//we don't need the translucent flag this is handled by the theme
StatusBarHelper.SetTranslucentStatusFlag(Activity, false);
//set the statusbarcolor transparent to remove the black shadow
StatusBarHelper.SetStatusBarColor(Activity, Color.Transparent);
}
StatusBarHelper.SetLightStatusBar(Activity, false);`
To create the main view (with the drawer):
_drawerLayout = new DrawerLayout(inflater.Context)
{
LayoutParameters = new DrawerLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent),
};
ViewCompat.SetOnApplyWindowInsetsListener(_drawerLayout, this); // This only works from lollipop
using (FrameLayout contentContainer = new FrameLayout(inflater.Context))
{
contentContainer.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent);
// Sets fullscreen to be able to go under the status bar
if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
{
// Already works since Kitkat, but since SetOnApplyWindowInsets only works from lollipop, for the moment we enable this later
contentContainer.SystemUiVisibility = (StatusBarVisibility)(SystemUiFlags.LayoutStable | SystemUiFlags.LayoutFullscreen | SystemUiFlags.LayoutHideNavigation);
}
// Make the content ViewGroup ignore insets so that it does not use the default padding
ViewCompat.SetOnApplyWindowInsetsListener(contentContainer, this);
// Scrim view. This is used to paint under the status bar the color that we want
using (View statusBarScrim = new View(inflater.Context))
{
statusBarScrim.Id = Resource.Id.scrim_view;
statusBarScrim.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, 0);
statusBarScrim.SetBackgroundColor(new Color(ResourcesCompat.GetColor(Resources, Resource.Color.primaryDark, null)));
ViewCompat.SetOnApplyWindowInsetsListener(statusBarScrim, this);
contentContainer.AddView(statusBarScrim);
}
//Create main content (toolbar and fragment container)
using (var mainContent = CreateMainContent(inflater))
{
contentContainer.AddView(mainContent);
}
contentContainer.SetFitsSystemWindows(true);
_drawerLayout.AddView(contentContainer);
}
Finally the code for the insetListener:
// This is used to handle the scrim view
// The scrim view is used to cover the status bar with a color
// The scrim consumes the top inset by getting its height
// All other views are ignored
public WindowInsetsCompat OnApplyWindowInsets(View v, WindowInsetsCompat insets)
{
// Check if it's the scrim view
// If it's not the scrim it will not consume the insets
if (v.Id == Resource.Id.scrim_view)
{
var topInset = insets.SystemWindowInsetTop;
if (v.LayoutParameters.Height != topInset)
{
v.LayoutParameters.Height = topInset;
v.RequestLayout();
}
}
return insets;
}
To create the Context Action Menu I use the StartSupportActionMode
and in the OnCreateActionMode
I'm just setting up the menu. The status bar becomes black (Context Action Mode adds a view like the scrim I'm using, but I haven't found a way to color it).
There's an item in this menu that navigates to the screen you see in the image I attached previously. When this item is pressed i call _actionMode.Finish()
and then navigate there. The result is that the Context Action Mode toolbar disappears but this black scrim view doesn't.
If I add a delay before navigating this error doesn't occur, so I'm thinking it has something to do with the animation? Either way, solving things with delay is always bad practice because it will be different in each device.
Okay, so I'm pretty sure this must be a bug with AppCompat's ActionMode. In the end, I was lucky and setting FitSystemWindows on the fragment navigated to seems to fix the issue.
Also, I found how to set the color of the scrim layout Action Mode adds without ever seeing the black bar.
I found the answer here https://stackoverflow.com/a/38702953/10054508 so all the credit goes to him. Either way, I'll paste it here:
<color name="abc_input_method_navigation_guard" tools:override="true">@color/primary_dark</color>