Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>

<pages:BasePage
x:Class="CommunityToolkit.Maui.Sample.Pages.Behaviors.StatusBarBehaviorPage"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
Expand Down Expand Up @@ -118,9 +119,9 @@
Value="{Binding BlueSliderValue}" />
<HorizontalStackLayout>
<Label Text="Alpha: " />
<Label Text="{Binding AlphaSliderValue}"/>
<Label Text="{Binding AlphaSliderValue}" />
</HorizontalStackLayout>

<Stepper
HorizontalOptions="Start"
Margin="20,0"
Expand All @@ -130,36 +131,47 @@
Value="{Binding AlphaSliderValue}" />

<Label Text="Select StatusBar and NavigationBar style" />

<HorizontalStackLayout Spacing="15">



<RadioButton
Content="Default"
IsChecked="{Binding IsDefaultChecked}"
VerticalOptions="Center" />
<HorizontalStackLayout Spacing="15">
<RadioButton IsChecked="{Binding IsDefaultChecked}"
VerticalOptions="Center">
<RadioButton.Content>
<Label
Margin="10,0,0,0"
Text="Default"
VerticalOptions="Center"
VerticalTextAlignment="Center" />
</RadioButton.Content>
</RadioButton>

<RadioButton VerticalOptions="Center" IsChecked="{Binding IsLightContentChecked}">
<RadioButton IsChecked="{Binding IsLightContentChecked}"
VerticalOptions="Center">
<RadioButton.Content>
<Label Text="Light Content" Margin="10,0,0,0" VerticalTextAlignment="Center"
VerticalOptions="Center" />
<Label
Margin="10,0,0,0"
Text="Light&#10;Content"
VerticalOptions="Center"
VerticalTextAlignment="Center" />
</RadioButton.Content>
</RadioButton>

<RadioButton IsChecked="{Binding IsDarkContentChecked}">
<RadioButton IsChecked="{Binding IsDarkContentChecked}"
VerticalOptions="Center">
<RadioButton.Content>
<Label Text="Dark Content" Margin="10,0,0,0" VerticalTextAlignment="Center"
VerticalOptions="Center" />
<Label
Margin="10,0,0,0"
Text="Dark&#10;Content"
VerticalOptions="Center"
VerticalTextAlignment="Center" />
</RadioButton.Content>
</RadioButton>

</HorizontalStackLayout>

<Button
x:Name="ModalPageButton"
HorizontalOptions="Center"
VerticalOptions="Center"/>
VerticalOptions="Center" />
</VerticalStackLayout>
</ScrollView>
</pages:BasePage>
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@
ThumbColor="Blue"
Value="{Binding BlueSliderValue}" />

<VerticalStackLayout Spacing="15">
<Label Text="Select NavigationBar style" />
<Label Text="Select NavigationBar style" />
<HorizontalStackLayout Spacing="15">

<RadioButton IsChecked="{Binding IsDefaultChecked}" VerticalOptions="Center">
<RadioButton.Content>
Expand All @@ -125,7 +125,7 @@
<RadioButton.Content>
<Label
Margin="10,0,0,0"
Text="Light Content"
Text="Light&#10;Content"
VerticalOptions="Center"
VerticalTextAlignment="Center" />
</RadioButton.Content>
Expand All @@ -135,12 +135,12 @@
<RadioButton.Content>
<Label
Margin="10,0,0,0"
Text="Dark Content"
Text="Dark&#10;Content"
VerticalOptions="Center"
VerticalTextAlignment="Center" />
</RadioButton.Content>
</RadioButton>
</VerticalStackLayout>
</HorizontalStackLayout>
</VerticalStackLayout>
</ScrollView>
</pages:BasePage>
Original file line number Diff line number Diff line change
Expand Up @@ -5,54 +5,54 @@ namespace CommunityToolkit.Maui.Sample.ViewModels.Behaviors;

public partial class StatusBarBehaviorViewModel : BaseViewModel
{
public Color StatusBarColor => Color.FromRgba(RedSliderValue, GreenSliderValue, BlueSliderValue, AlphaSliderValue);

public StatusBarStyle StatusBarStyle
{
get
{
if (IsDefaultChecked)
{
return StatusBarStyle.Default;
}
if (IsLightContentChecked)
{
return StatusBarStyle.LightContent;
}
if (IsDarkContentChecked)
{
return StatusBarStyle.DarkContent;
}

throw new NotSupportedException($"{nameof(StatusBarStyle)} type is not supported.");
}
}

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(StatusBarColor))]
public partial double RedSliderValue { get; set; }
public partial double RedSliderValue { get; set; } = 0.5;

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(StatusBarColor))]
public partial double GreenSliderValue { get; set; }
public partial double GreenSliderValue { get; set; } = 0.5;

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(StatusBarColor))]
public partial double BlueSliderValue { get; set; }
public partial double BlueSliderValue { get; set; } = 0.5;

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(StatusBarColor))]
public partial double AlphaSliderValue { get; set; } = 1;

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(StatusBarStyle))]
public partial bool IsLightContentChecked { get; set; } = true;
public partial bool IsLightContentChecked { get; set; }

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(StatusBarStyle))]
public partial bool IsDarkContentChecked { get; set; } = true;
public partial bool IsDarkContentChecked { get; set; }

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(StatusBarStyle))]
public partial bool IsDefaultChecked { get; set; } = true;

public Color StatusBarColor => Color.FromRgba(RedSliderValue, GreenSliderValue, BlueSliderValue, AlphaSliderValue);

public StatusBarStyle StatusBarStyle
{
get
{
if (IsDefaultChecked)
{
return StatusBarStyle.Default;
}
if (IsLightContentChecked)
{
return StatusBarStyle.LightContent;
}
if (IsDarkContentChecked)
{
return StatusBarStyle.DarkContent;
}

throw new NotSupportedException($"{nameof(StatusBarStyle)} {StatusBarStyle} is not supported.");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using Android.Views;
using Microsoft.Maui.Platform;
using Activity = Android.App.Activity;
using DialogFragment = AndroidX.Fragment.App.DialogFragment;

namespace CommunityToolkit.Maui.Core.Extensions;

Expand All @@ -8,16 +11,34 @@ namespace CommunityToolkit.Maui.Core.Extensions;
public static class AndroidWindowExtensions
{
/// <summary>
/// Gets the current window associated with the specified activity.
/// Gets the current visible window associated with the specified activity.
/// </summary>
/// <param name="activity">The activity.</param>
/// <returns>The current window.</returns>
/// <exception cref="InvalidOperationException">Thrown when the activity window is null.</exception>
public static Window GetCurrentWindow(this Activity activity)
{
var window = activity.Window ?? throw new InvalidOperationException($"{nameof(activity.Window)} cannot be null");
window.ClearFlags(WindowManagerFlags.TranslucentStatus);
window.AddFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);
return window;
Window? currentWindow = null;

var fragmentManager = activity.GetFragmentManager();
if (fragmentManager is not null && fragmentManager.Fragments.OfType<DialogFragment>().Any())
{
var fragments = fragmentManager.Fragments;
for (var i = fragments.Count - 1; i >= 0; i--)
{
if (fragments[i] is DialogFragment { Dialog: { IsShowing: true, Window: not null }, IsVisible: true } dialogFragment)
{
currentWindow = dialogFragment.Dialog.Window;
break;
}
}
}
Comment thread
TheCodeTraveler marked this conversation as resolved.

currentWindow ??= activity.Window ?? throw new InvalidOperationException($"{nameof(activity.Window)} cannot be null");

currentWindow.ClearFlags(WindowManagerFlags.TranslucentStatus);
currentWindow.AddFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);

return currentWindow;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,57 +35,58 @@ static void PlatformSetColor(Color color)
return;
}

if (Activity.Window is not null)
if (Activity.GetCurrentWindow() is not Window { DecorView.RootView: not null } window)
{
var platformColor = color.ToPlatform();
return;
}
Comment thread
TheCodeTraveler marked this conversation as resolved.

if (OperatingSystem.IsAndroidVersionAtLeast(35))
{
const string statusBarOverlayTag = "StatusBarOverlay";
var platformColor = color.ToPlatform();

var window = Activity.GetCurrentWindow();
if (OperatingSystem.IsAndroidVersionAtLeast(35))
{
const string statusBarOverlayTag = "StatusBarOverlay";

var decorGroup = (ViewGroup)window.DecorView;
var statusBarOverlay = decorGroup.FindViewWithTag(statusBarOverlayTag);
var decorGroup = (ViewGroup)window.DecorView.RootView;
Comment thread
TheCodeTraveler marked this conversation as resolved.
var statusBarOverlay = decorGroup.FindViewWithTag(statusBarOverlayTag);
Comment thread
TheCodeTraveler marked this conversation as resolved.

if (statusBarOverlay is null)
{
var statusBarHeight = Activity.Resources?.GetIdentifier("status_bar_height", "dimen", "android") ?? 0;
var statusBarPixelSize = statusBarHeight > 0 ? Activity.Resources?.GetDimensionPixelSize(statusBarHeight) ?? 0 : 0;
if (statusBarOverlay is null)
{
var statusBarHeight = Activity.Resources?.GetIdentifier("status_bar_height", "dimen", "android") ?? 0;
var statusBarPixelSize = statusBarHeight > 0 ? Activity.Resources?.GetDimensionPixelSize(statusBarHeight) ?? 0 : 0;

statusBarOverlay = new(Activity)
statusBarOverlay = new(Activity)
{
LayoutParameters = new FrameLayout.LayoutParams(Android.Views.ViewGroup.LayoutParams.MatchParent, statusBarPixelSize + 3)
{
LayoutParameters = new FrameLayout.LayoutParams(Android.Views.ViewGroup.LayoutParams.MatchParent, statusBarPixelSize + 3)
{
Gravity = GravityFlags.Top
}
};

decorGroup.AddView(statusBarOverlay);
statusBarOverlay.SetZ(0);
}
Gravity = GravityFlags.Top
}
};

Comment thread
TheCodeTraveler marked this conversation as resolved.
statusBarOverlay.SetBackgroundColor(platformColor);
}
else
{
Activity.Window.SetStatusBarColor(platformColor);
statusBarOverlay.Tag = statusBarOverlayTag;
decorGroup.AddView(statusBarOverlay);
statusBarOverlay.SetZ(0);
}

bool isColorTransparent = platformColor == PlatformColor.Transparent;
if (isColorTransparent)
{
Activity.Window.ClearFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);
Activity.Window.SetFlags(WindowManagerFlags.LayoutNoLimits, WindowManagerFlags.LayoutNoLimits);
}
else
{
Activity.Window.ClearFlags(WindowManagerFlags.LayoutNoLimits);
Activity.Window.SetFlags(WindowManagerFlags.DrawsSystemBarBackgrounds, WindowManagerFlags.DrawsSystemBarBackgrounds);
}
statusBarOverlay.SetBackgroundColor(platformColor);
}
else
{
window.SetStatusBarColor(platformColor);
}

WindowCompat.SetDecorFitsSystemWindows(Activity.Window, !isColorTransparent);
bool isColorTransparent = platformColor == PlatformColor.Transparent;
if (isColorTransparent)
{
window.ClearFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know any other way to deal with issue of status bar transparency but settings and clearing flags can and will interfere with developers attempts to set or use full screen and in a test app I had to remove all the settings and clearing of flags to have my app do what I wanted. I removed it throughout the toolkit where I found it in statusbar.

I am not sure what we should do here. This is more a comment about the current state of the behavior of hiding/showing status bar is a complicated mess atm and depending on API level settings these options will have completely different behavior on each API.

I do not advocate ripping out the flags I am simply stating all of my use cases do require it. It would have significant impact on all API below 36 so I am not suggesting we do that. Just maybe add checks and block the changes for android 36?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be a good idea to add full-screen mode to CommunityToolkit.Maui so it doesn't interfere with the color change. We could also use an IsVisible boolean on the status bar and navigation bar.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@IgrisModz sure! What specifically do we need to add?

Do you have any links to documentation you could share?

window.SetFlags(WindowManagerFlags.LayoutNoLimits, WindowManagerFlags.LayoutNoLimits);
}
else
{
window.ClearFlags(WindowManagerFlags.LayoutNoLimits);
window.SetFlags(WindowManagerFlags.DrawsSystemBarBackgrounds, WindowManagerFlags.DrawsSystemBarBackgrounds);
}

WindowCompat.SetDecorFitsSystemWindows(window, !isColorTransparent);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is deprecated on Android API 36. It is highly recommended that we add a check and only use it on an OS using a lower API.

}

static void PlatformSetStyle(StatusBarStyle style)
Expand All @@ -98,23 +99,23 @@ static void PlatformSetStyle(StatusBarStyle style)
switch (style)
{
case StatusBarStyle.DarkContent:
SetStatusBarAppearance(Activity, true);
SetStatusBarAppearance(true);
break;

case StatusBarStyle.Default:
case StatusBarStyle.LightContent:
SetStatusBarAppearance(Activity, false);
SetStatusBarAppearance(false);
break;

default:
throw new NotSupportedException($"{nameof(StatusBarStyle)} {style} is not yet supported on Android");
}
}

static void SetStatusBarAppearance(Activity activity, bool isLightStatusBars)
static void SetStatusBarAppearance(bool isLightStatusBars)
{
var window = activity.GetCurrentWindow();
if (WindowCompat.GetInsetsController(window, window.DecorView) is WindowInsetsControllerCompat windowController)
if (Activity.GetCurrentWindow() is Window window
&& WindowCompat.GetInsetsController(window, window.DecorView) is WindowInsetsControllerCompat windowController)
{
windowController.AppearanceLightStatusBars = isLightStatusBars;
}
Expand Down
Loading
Loading