Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[iOS] StatusBarBehavior does not occupy entire notch - fix #2309

Merged
merged 9 commits into from
Jan 16, 2025
2 changes: 1 addition & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ variables:
PathToCommunityToolkitAnalyzersBenchmarkCsproj: 'src/CommunityToolkit.Maui.Analyzers.Benchmarks/CommunityToolkit.Maui.Analyzers.Benchmarks.csproj'
DotNetMauiRollbackFile: 'https://maui.blob.core.windows.net/metadata/rollbacks/8.0.6.json'
CommunityToolkitSampleApp_Xcode_Version: '16.2'
CommunityToolkitLibrary_Xcode_Version: '16.1'
CommunityToolkitLibrary_Xcode_Version: '16.2'

trigger:
branches:
Expand Down
7 changes: 2 additions & 5 deletions samples/CommunityToolkit.Maui.Sample/Pages/Base/BasePage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@

namespace CommunityToolkit.Maui.Sample.Pages;

public abstract class BasePage<TViewModel> : BasePage where TViewModel : BaseViewModel
public abstract class BasePage<TViewModel>(TViewModel viewModel) : BasePage(viewModel)
where TViewModel : BaseViewModel
{
protected BasePage(TViewModel viewModel) : base(viewModel)
{
}

public new TViewModel BindingContext => (TViewModel)base.BindingContext;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
xmlns:mct="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:pages="clr-namespace:CommunityToolkit.Maui.Sample.Pages"
xmlns:vm="clr-namespace:CommunityToolkit.Maui.Sample.ViewModels.Behaviors"
xmlns:ios="clr-namespace:Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;assembly=Microsoft.Maui.Controls"
ios:Page.UseSafeArea="True"
Title="StatusBarBehavior"
x:DataType="vm:StatusBarBehaviorViewModel"
x:TypeArguments="vm:StatusBarBehaviorViewModel"
Expand Down Expand Up @@ -81,7 +83,7 @@

<ScrollView Padding="{StaticResource ContentPadding}">

<VerticalStackLayout Padding="15,0" Spacing="30">
<VerticalStackLayout Padding="15,0" Spacing="30" IgnoreSafeArea="False">

<Label Text="Slide to change StatusBar color" />

Expand Down
126 changes: 50 additions & 76 deletions src/CommunityToolkit.Maui.Core/Platform/StatusBar/StatusBar.ios.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,91 +11,73 @@ static partial class StatusBar
/// <summary>
/// Method to update the status bar size.
/// </summary>
public static void UpdateBarSize()
public static void SetBarSize(bool isUsingSafeArea)
{
if (OperatingSystem.IsIOSVersionAtLeast(13))
var communityToolkitStatusBarTag = new IntPtr(38482);
foreach (var window in UIApplication.SharedApplication.Windows)
{
var statusBarTag = new IntPtr(38482);
foreach (var window in UIApplication.SharedApplication.Windows)
var statusBarFrame = window.WindowScene?.StatusBarManager?.StatusBarFrame;
if (statusBarFrame is null)
{
var statusBar = window.ViewWithTag(statusBarTag);
var statusBarFrame = window.WindowScene?.StatusBarManager?.StatusBarFrame;
if (statusBarFrame is null)
{
continue;
}

statusBar ??= new UIView(statusBarFrame.Value);
statusBar.Tag = statusBarTag;
statusBar.Frame = UIApplication.SharedApplication.StatusBarFrame;
var statusBarSubViews = window.Subviews.Where(x => x.Tag == statusBarTag).ToList();
foreach (var statusBarSubView in statusBarSubViews)
{
statusBarSubView.RemoveFromSuperview();
}

window.AddSubview(statusBar);

TryUpdateStatusBarAppearance(window);
continue;
}
}
else
{
if (UIApplication.SharedApplication.ValueForKey(new NSString("statusBar")) is UIView statusBar)

var statusBar = window.ViewWithTag(communityToolkitStatusBarTag) ?? new UIView(statusBarFrame.Value);
statusBar.Tag = communityToolkitStatusBarTag;
statusBar.Frame = GetStatusBarFrame(window, isUsingSafeArea);

var statusBarSubViews = window.Subviews.Where(x => x.Tag == communityToolkitStatusBarTag).ToList();
foreach (var statusBarSubView in statusBarSubViews)
{
statusBar.Frame = UIApplication.SharedApplication.StatusBarFrame;
statusBarSubView.RemoveFromSuperview();
}

TryUpdateStatusBarAppearance();
window.AddSubview(statusBar);

TryUpdateStatusBarAppearance(window);
}
}

static void PlatformSetColor(Color color)
{
var uiColor = color.ToPlatform();

if (OperatingSystem.IsIOSVersionAtLeast(13))

var statusBarTag = new IntPtr(38482);
foreach (var window in UIApplication.SharedApplication.Windows)
{
var statusBarTag = new IntPtr(38482);
foreach (var window in UIApplication.SharedApplication.Windows)
var statusBar = window.ViewWithTag(statusBarTag);
var statusBarFrame = window.WindowScene?.StatusBarManager?.StatusBarFrame;
if (statusBarFrame is null)
{
var statusBar = window.ViewWithTag(statusBarTag);
var statusBarFrame = window.WindowScene?.StatusBarManager?.StatusBarFrame;
if (statusBarFrame is null)
{
continue;
}

// ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract
// window.ViewWithTag(tag) can return null
statusBar ??= new UIView(statusBarFrame.Value);
statusBar.Tag = statusBarTag;
statusBar.BackgroundColor = uiColor;
statusBar.TintColor = uiColor;
statusBar.Frame = UIApplication.SharedApplication.StatusBarFrame;
var statusBarSubViews = window.Subviews.Where(x => x.Tag == statusBarTag).ToList();
foreach (var statusBarSubView in statusBarSubViews)
{
statusBarSubView.RemoveFromSuperview();
}

window.AddSubview(statusBar);

TryUpdateStatusBarAppearance(window);
continue;
}
}
else
{
if (UIApplication.SharedApplication.ValueForKey(new NSString("statusBar")) is UIView statusBar
&& statusBar.RespondsToSelector(new ObjCRuntime.Selector("setBackgroundColor:")))

statusBar ??= new UIView(statusBarFrame.Value);
statusBar.Tag = statusBarTag;
statusBar.BackgroundColor = uiColor;
statusBar.TintColor = uiColor;

var statusBarSubViews = window.Subviews.Where(x => x.Tag == statusBarTag).ToList();
foreach (var statusBarSubView in statusBarSubViews)
{
statusBar.BackgroundColor = uiColor;
statusBarSubView.RemoveFromSuperview();
}

TryUpdateStatusBarAppearance();
window.AddSubview(statusBar);

TryUpdateStatusBarAppearance(window);
}
}

static CGRect GetStatusBarFrame(in UIWindow window, in bool isUsingSafeArea)
{
var statusBarFrame = UIApplication.SharedApplication.StatusBarFrame;

return isUsingSafeArea
? new CGRect(statusBarFrame.X, statusBarFrame.Y, statusBarFrame.Width, window.SafeAreaInsets.Top)
: statusBarFrame;
}

static void PlatformSetStyle(StatusBarStyle statusBarStyle)
{
var uiStyle = statusBarStyle switch
Expand All @@ -113,22 +95,14 @@ static void PlatformSetStyle(StatusBarStyle statusBarStyle)

static bool TryUpdateStatusBarAppearance()
{
if (OperatingSystem.IsIOSVersionAtLeast(13))
{
var didUpdateAllStatusBars = true;
var didUpdateAllStatusBars = true;

foreach (var window in UIApplication.SharedApplication.Windows)
{
didUpdateAllStatusBars &= TryUpdateStatusBarAppearance(window);
}

return didUpdateAllStatusBars;
}
else
foreach (var window in UIApplication.SharedApplication.Windows)
{
var window = UIApplication.SharedApplication.KeyWindow;
return TryUpdateStatusBarAppearance(window);
didUpdateAllStatusBars &= TryUpdateStatusBarAppearance(window);
}

return didUpdateAllStatusBars;
}

static bool TryUpdateStatusBarAppearance(UIWindow? window)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,48 +78,53 @@ public StatusBarApplyOn ApplyOn

/// <inheritdoc />
#if IOS
protected override void OnAttachedTo(Page bindable, UIKit.UIView platformView)
protected override void OnAttachedTo(Page page, UIKit.UIView platformView)
#elif ANDROID
protected override void OnAttachedTo(Page bindable, Android.Views.View platformView)
protected override void OnAttachedTo(Page page, Android.Views.View platformView)
#else
protected override void OnAttachedTo(Page bindable, object platformView)
protected override void OnAttachedTo(Page page, object platformView)
#endif
{
base.OnAttachedTo(bindable, platformView);
base.OnAttachedTo(page, platformView);

if (ApplyOn is StatusBarApplyOn.OnBehaviorAttachedTo)
{
#if IOS
StatusBar.SetBarSize(Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific.Page.GetUseSafeArea(page));
#endif

StatusBar.SetColor(StatusBarColor);
StatusBar.SetStyle(StatusBarStyle);
}

bindable.NavigatedTo += OnPageNavigatedTo;
page.NavigatedTo += OnPageNavigatedTo;
#if IOS
bindable.SizeChanged += OnPageSizeChanged;
page.SizeChanged += OnPageSizeChanged;
#endif
}

/// <inheritdoc />
#if IOS
protected override void OnDetachedFrom(Page bindable, UIKit.UIView platformView)
protected override void OnDetachedFrom(Page page, UIKit.UIView platformView)
#elif ANDROID
protected override void OnDetachedFrom(Page bindable, Android.Views.View platformView)
protected override void OnDetachedFrom(Page page, Android.Views.View platformView)
#else
protected override void OnDetachedFrom(Page bindable, object platformView)
protected override void OnDetachedFrom(Page page, object platformView)
#endif
{
#if IOS
bindable.SizeChanged -= OnPageSizeChanged;
page.SizeChanged -= OnPageSizeChanged;
#endif
base.OnDetachedFrom(bindable, platformView);
base.OnDetachedFrom(page, platformView);

bindable.NavigatedTo -= OnPageNavigatedTo;
page.NavigatedTo -= OnPageNavigatedTo;
}

#if IOS
static void OnPageSizeChanged(object? sender, EventArgs e)
{
StatusBar.UpdateBarSize();
ArgumentNullException.ThrowIfNull(sender);
StatusBar.SetBarSize(Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific.Page.GetUseSafeArea((Page)sender));
}
#endif

Expand Down
Loading