maui
maui copied to clipboard
Fullscreen
Description
I would like the option to show the app in full screen on Windows (without any border or title) and Android ("immersive" mode).
Public API Changes
'''csharp var contentpage = new ContentPage; Contenpage.Fullscreen= true; //this will make the window borderless and fullscreen
//this is just an example, any other way would be great
Intended Use-Case
My application need is a presentation display and require fullscreen.
I'd really like to have that functionality too.
We've moved this issue to the Future milestone. This means that it is not going to be worked on for the coming release. We will reassess the issue following the current release and consider this item at that time.
Has this feature been reconsidered or already being implemented?
This is a sorely needed feature for me. Currently I work with a reading screen that when I go up the page I need to hide the status bar and the navigation buttons.
Generally, it is possible for Android and iOS to have a "fullscreen" or "immersive" experience. However, it is very tedious to implement it separately for each platform. It would be convenient to have this functionality either directly in MAUI or in the Community Toolkit.
net7.0rc-1
Windows
MauiProgram.cs
#if WINDOWS
// using Microsoft.Maui.LifecycleEvents;
// #if WINDOWS
// using Microsoft.UI;
// using Microsoft.UI.Windowing;
// using Windows.Graphics;
// #endif
builder.ConfigureLifecycleEvents(events =>
{
events.AddWindows(windowsLifecycleBuilder =>
{
windowsLifecycleBuilder.OnWindowCreated(window =>
{
window.ExtendsContentIntoTitleBar = false;
var handle = WinRT.Interop.WindowNative.GetWindowHandle(window);
var id = Win32Interop.GetWindowIdFromWindow(handle);
var appWindow = AppWindow.GetFromWindowId(id);
switch (appWindow.Presenter)
{
case OverlappedPresenter overlappedPresenter:
overlappedPresenter.SetBorderAndTitleBar(false, false);
overlappedPresenter.Maximize();
break;
}
});
});
});
#endif
Android
Platforms/Android/MainActivity.cs
[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize)]
public class MainActivity : MauiAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Platform.Init(this, savedInstanceState);
this.Window?.AddFlags(WindowManagerFlags.Fullscreen);
}
}
(Edit MainPage.xml if you are still not full screen in windows)
<?xml version="1.0" encoding="UTF-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Adverse_Player"
x:Class="YourApp.MainPage"
Title=""
NavigationPage.HasNavigationBar="False">
<BlazorWebView HostPage="wwwroot/index.html">
<BlazorWebView.RootComponents>
<RootComponent Selector="#app" ComponentType="{x:Type local:Main}" />
</BlazorWebView.RootComponents>
</BlazorWebView>
</ContentPage>
net7.0rc-1
Windows
MauiProgram.cs #if WINDOWS // using Microsoft.Maui.LifecycleEvents; // #if WINDOWS // using Microsoft.UI; // using Microsoft.UI.Windowing; // using Windows.Graphics; // #endif builder.ConfigureLifecycleEvents(events => { events.AddWindows(windowsLifecycleBuilder => { windowsLifecycleBuilder.OnWindowCreated(window => { window.ExtendsContentIntoTitleBar = false; var handle = WinRT.Interop.WindowNative.GetWindowHandle(window); var id = Win32Interop.GetWindowIdFromWindow(handle); var appWindow = AppWindow.GetFromWindowId(id); switch (appWindow.Presenter) { case OverlappedPresenter overlappedPresenter: overlappedPresenter.SetBorderAndTitleBar(false, false); overlappedPresenter.Maximize(); break; } }); }); }); #endif
Android
Platforms/Android/MainActivity.cs [Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize)] public class MainActivity : MauiAppCompatActivity { protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); Platform.Init(this, savedInstanceState); this.Window?.AddFlags(WindowManagerFlags.Fullscreen); } }
(Edit MainPage.xml if you are still not full screen in windows)
<?xml version="1.0" encoding="UTF-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:Adverse_Player" x:Class="YourApp.MainPage" Title="" NavigationPage.HasNavigationBar="False"> <BlazorWebView HostPage="wwwroot/index.html"> <BlazorWebView.RootComponents> <RootComponent Selector="#app" ComponentType="{x:Type local:Main}" /> </BlazorWebView.RootComponents> </BlazorWebView> </ContentPage>
What about for iOS and MacCatalyst (:
I am using the following code below. The application starts in full screen; however, when I enter a value into an entry the black box for the navigation buttons appears at the bottom of the screen. I have disabled the soft keyboard and navigation buttons which do not show. I am not able to make the black box background go away. Any help would be appreciated.
if (this.Window != null) { this.Window.AddFlags(WindowManagerFlags.Fullscreen); this.Window.SetFlags(WindowManagerFlags.Fullscreen, WindowManagerFlags.Fullscreen); if (Build.VERSION.SdkInt >= BuildVersionCodes.R) { #pragma warning disable CA1416 try { IWindowInsetsController wicController = Window.InsetsController; if (wicController != null) { wicController.Hide(WindowInsets.Type.Ime()); wicController.Hide(WindowInsets.Type.NavigationBars()); wicController.Hide(WindowInsets.Type.SystemBars()); wicController.Hide(WindowInsets.Type.StatusBars()); } } catch { } #pragma warning restore CA1416 } else { #pragma warning disable CS0618 try { Android.Views.View decorView = Window.DecorView; int uiOptions = (int)decorView.SystemUiVisibility; uiOptions |= (int)SystemUiFlags.Fullscreen; uiOptions |= (int)SystemUiFlags.HideNavigation; uiOptions |= (int)SystemUiFlags.Immersive; uiOptions |= (int)SystemUiFlags.ImmersiveSticky; uiOptions |= (int)SystemUiFlags.LayoutHideNavigation; uiOptions |= (int)SystemUiFlags.LayoutStable; uiOptions |= (int)SystemUiFlags.LayoutFullscreen; uiOptions |= (int)SystemUiFlags.LowProfile; Window.DecorView.SystemUiVisibility = (StatusBarVisibility)uiOptions; } catch { } #pragma warning restore CS0618 } }
I believe that is the taskbar not the navigation bar. You can either disable it in system settings or take a look at https://github.com/dotnet/maui/issues/8575#issuecomment-1177120915
https://android.stackexchange.com/questions/249098/how-to-disable-bottom-app-toolbar-on-samsung-tab-running-android-12
Anyone looking for a centralized way of achieving fullscreen without having to mess with the Platform specific files can use the code below. You can also use it to switch the fullscreen on and off based on some app logic. Our requirement was to set fullscreen mode according to user settings.
I haven't figured out yet how to do it programmatically for iOS and MacCatalyst. This code is for Android and Windows only. It took me a while to figure out the correct casting and code with lots of debugging... as the documentation for all this is practically non-existent with different versions of Dot Net having different syntax, adding to the confusion.
Let me know if you find any bug :)
Dotnet: 7
In App.xaml.cs file:
using Application = Microsoft.Maui.Controls.Application;
using Platform = Microsoft.Maui.ApplicationModel.Platform;
#if ANDROID
using View = AndroidX.Core.View;
#endif
#if WINDOWS
using Microsoft.UI;
using Microsoft.UI.Windowing;
using WinRT;
using Microsoft.Maui.Controls;
#endif
namespace MyApp;
public partial class App : Application
{
private bool FullScreenMode { get; set; }
public App()
{
FullScreenMode = false;
InitializeComponent();
MainPage = new MainPage();
}
protected override Window CreateWindow(IActivationState? activationState)
{
Window window = base.CreateWindow(activationState);
window.Created += (s, e) =>
{
FullScreenMode = true; //NOTE: Change this to fetch the value true/false according to your app logic.
SetFullScreen(s, e);
};
window.Resumed += (s, e) =>
{
//When resumed, the nav & status bar reappeared for android.
//Fixing it by calling SetFullScreen again on resume,
//If fullscreen had been set.
//Not sure if it is needed for windows. Haven't tested yet.
if (FullScreenMode)
{
SetFullScreen(s, e);
}
};
return window;
}
private void SetFullScreen(object? sender, EventArgs eventArgs)
{
#if ANDROID
SetFullScreenAndroid();
#endif
#if WINDOWS
SetFullScreenWindows(sender, eventArgs);
#endif
}
private void SetFullScreenAndroid()
{
#if ANDROID
var activity = Platform.CurrentActivity;
if (activity == null || activity.Window == null) return;
View.WindowCompat.SetDecorFitsSystemWindows(activity.Window, !FullScreenMode);
var windowInsetsControllerCompat = View.WindowCompat.GetInsetsController(activity.Window, activity.Window.DecorView);
var types = View.WindowInsetsCompat.Type.StatusBars() |
View.WindowInsetsCompat.Type.NavigationBars();
if(FullScreenMode)
{
windowInsetsControllerCompat.SystemBarsBehavior = View.WindowInsetsControllerCompat.BehaviorShowBarsBySwipe;
windowInsetsControllerCompat.Hide(types);
}
else
{
windowInsetsControllerCompat.Show(types);
}
#endif
}
private void SetFullScreenWindows(object? sender, EventArgs eventArgs)
{
#if WINDOWS
if(sender is not null)
{
var currentWindow = sender.As<Window>();
var uiWindow = currentWindow.Handler.PlatformView.As<MauiWinUIWindow>();
var handle = WinRT.Interop.WindowNative.GetWindowHandle(uiWindow);
var id = Win32Interop.GetWindowIdFromWindow(handle);
var appWindow = AppWindow.GetFromWindowId(id);
switch (appWindow.Presenter)
{
case OverlappedPresenter overlappedPresenter:
//uiWindow.ExtendsContentIntoTitleBar = true;
if(FullScreenMode) {
overlappedPresenter.SetBorderAndTitleBar(false, false);
overlappedPresenter.Maximize();
}
else
{
overlappedPresenter.SetBorderAndTitleBar(true, true);
overlappedPresenter.Restore();
}
break;
}
}
#endif
}
}
Hi jasonmillernc99, thanks a lot for the post. This works great. Only thing in order to achieve real full screen in Windows without showing the titlebar:
//uiWindow.ExtendsContentIntoTitleBar = true;
needs to be changed to:
uiWindow.ExtendsContentIntoTitleBar = false;
Any updates? Fullscreen capability can be a useful feature for desktop apps both Mac and Windows, as it allows users to focus solely on the application without any distractions from other open windows or desktop icons. This can be particularly helpful for applications that require full attention, such as video editing, gaming, or graphic design.
@mouralabank it is already possible today, see the above provided code snippets. I also wrote about it here: https://blog.verslu.is/maui/full-screen-disable-minimize-maximize-for-net-maui-windows-apps/
The API in .NET MAUI could definitely be easy, but seeing that there are good options available to do this today, I don't think this will be prioritized soon.
@mouralabank it is already possible today, see the above provided code snippets. I also wrote about it here: https://blog.verslu.is/maui/full-screen-disable-minimize-maximize-for-net-maui-windows-apps/
The API in .NET MAUI could definitely be easy, but seeing that there are good options available to do this today, I don't think this will be prioritized soon.
@jfversluis Thanks for the tip, very useful! I want to give you a suggestion, I believe that videos for MAUI Desktop can be very impactful to promote and expand the community and resources! I see a lot of potential in the MAUI desktop yet to be discovered and growing!!!
I have started a discussion in the community toolkit to talk about adding full screen for both windows and android to the toolkit. I have tested my code and added it to a fork of toolkit and spent some time testing code. It still needs discussion and I am sure my code needs revision but I am waiting on someone to review the discussion and decide if SetFullScreen() and RestoreScreen() will make it into the toolkit. Here is a link to discussion if anyone wants to comment or like it I would appreciate feedback.
Link to discussion: https://github.com/CommunityToolkit/Maui/discussions/1123 Link to fork: https://github.com/ne0rrmatrix/Maui/tree/FullScreen
@dimplevador , I've been experimenting with different methods to achieve a full immersive experience on Android devices, and I came across your workaround code. I wanted to thank you for sharing it. I tested the code on my Android 30 device, and it worked perfectly.
However, I encountered issues when I tried running it on my other testing device, which runs on Android 29. On the Android 29 device, the mobile status bar area is completely covered with a black strip, and the keyboard overlaps text input fields. This behavior is preventing me from achieving the desired immersive experience.
I would greatly appreciate any suggestions or workarounds that you or anyone else could offer to address this problem. I'm also open to exploring alternative approaches or libraries that can provide a consistent fullscreen experience across different Android versions.
Thank you in advance for any assistance or insights you can provide!
@Brionvega Glad it helped :)
Regarding Keyboard overlapping text input fields, you have to set WindowSoftInputMode = SoftInput.AdjustResize
in your MainActivity.cs ConfigurationChanges. That had worked for me.
Another solution for it is in App.xaml.cs constructor, you have to add this line:
Current?.On<Microsoft.Maui.Controls.PlatformConfiguration.Android>().UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize);
Try both. Whichever works :)
======
I don't have a device with Android 29 on hand but you can try the following code and see if it helps
private void SetFullScreenAndroid()
{
#if ANDROID
var activity = Platform.CurrentActivity;
if (activity == null || activity.Window == null) return;
View.WindowCompat.SetDecorFitsSystemWindows(activity.Window, !FullScreenMode);
var windowInsetsControllerCompat = View.WindowCompat.GetInsetsController(activity.Window, activity.Window.DecorView);
windowInsetsControllerCompat.SystemBarsBehavior = View.WindowInsetsControllerCompat.BehaviorShowTransientBarsBySwipe;
var types = View.WindowInsetsCompat.Type.StatusBars() |
View.WindowInsetsCompat.Type.NavigationBars();
if(FullScreenMode)
{
windowInsetsControllerCompat.Hide(types);
}
else
{
windowInsetsControllerCompat.Show(types);
}
#endif
}
@dimplevador Thank you so much for your response and for providing the additional guidance! I appreciate you sharing the updated code snippet for setting fullscreen on Android. I will integrate the updated code snippet you shared for setting fullscreen on Android into my project and test it out. Thank you once again for your help and suggestions. I really appreciate your assistance in resolving this issue :)
@dimplevador I tried the global one (i.e
Current?.On<Microsoft.Maui.Controls.PlatformConfiguration.Android>() .UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize);
)
And this actually works! thanks so much!
@dimplevador I tried the global one (i.e
Current?.On<Microsoft.Maui.Controls.PlatformConfiguration.Android>() .UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize);
) And this actually works! thanks so much!
@xx7Ahmed7xx Glad it worked :)
I need this for MacOS or rather a way how I can run a Maui app in the system tray of MacOS :)
Here is a repo that has support for Page full screen. https://github.com/ne0rrmatrix/MauiPageFullScreen Here is a link to Nuget package: https://www.nuget.org/packages/FullScreenStatus.Maui/
Supports Windows, IOS, and android. Can be used in shell, Navigation Page, and Tabbed Page.
Does not support Mac Catalyst. I have no idea how to do that. I can add hiding the bars but full screen on Mac still requires someone to make a lib and add it. I will be looking into doing that but I am having a hard time with visual studio on my mac mini. It is terribly difficult to work with. yes I know there are other solutions out there. Just have not had time to look into that yet.
Basic full screen function can be had quite easily by adding the following for Windows and Android the Program.cs code:
#if WINDOWS
builder.ConfigureLifecycleEvents(events =>
{
events.AddWindows(lifeCycleBuilder =>
{
lifeCycleBuilder.OnWindowCreated(w =>
{
w.ExtendsContentIntoTitleBar = false;
IntPtr wHandle = WinRT.Interop.WindowNative.GetWindowHandle(w);
WindowId windowId = Win32Interop.GetWindowIdFromWindow(wHandle);
AppWindow mauiWindow = AppWindow.GetFromWindowId(windowId);
mauiWindow.SetPresenter(AppWindowPresenterKind.FullScreen); // TO SET THE APP INTO FULL SCREEN
});
});
});
#endif
#if ANDROID
builder.ConfigureLifecycleEvents(events => {
events.AddAndroid(android => android.OnCreate((activity, bundle) => MakeFullScreen(activity)));
events.AddAndroid(android => android.OnCreate((activity, bundle) => MakeStatusBarTranslucent(activity)));
void MakeStatusBarTranslucent(Android.App.Activity activity) {
activity.Window.ClearFlags(Android.Views.WindowManagerFlags.TranslucentStatus);
activity.Window.SetStatusBarColor(Android.Graphics.Color.Transparent);
}
void MakeFullScreenApplication(Android.App.Application application) {
MakeFullScreen(application.GetActivity());
}
void MakeFullScreen(Android.App.Activity activity) {
activity.Window.DecorView.SystemUiVisibility = (Android.Views.StatusBarVisibility)(
Android.Views.SystemUiFlags.LayoutStable
| Android.Views.SystemUiFlags.LayoutHideNavigation
| Android.Views.SystemUiFlags.HideNavigation// hide nav bar
| Android.Views.SystemUiFlags.Immersive
| Android.Views.SystemUiFlags.ImmersiveSticky //so returns to immersive after pull down done
);
}
});
#endif
It would be good to add a simple third method to this for iOS but I cannot find one. I tried installing this package:
https://github.com/ne0rrmatrix/MauiPageFullScreen
But it does not work for iOS for me - nothing happens with its invocation, although it does work in Windows. I think that package is just using Shell and Navigation page functions which don't work unless your app is using a Shell or Navigation Page.
Does anyone know what the equivalent Builder code would be for iOS?
I see it claimed that one can make iOS full screen by adding the following values to the info.plist file:
<key>UIStatusBarHidden</key>
<true/>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
This is claimed here for Xamarin at least: https://learn.microsoft.com/en-us/answers/questions/863694/full-screen-app-on-ios-xamarin-forms
But this also does not work for me. I am Hot Reloading to iPhone XR as Debug build as I don't have a Mac. I note that MAUI states we cannot use custom App Icons or Splash Screen Icons when using this process. Perhaps this is the issue?
Can anyone confirm if the above method lets you build full screen for iOS or alternatively, any other ideas? To be clear, "full Screen" means it renders from the top of the screen to the bottom completely just like a splash screen.
Currently no matter what I do in iOS I get a white status bar at the top and a white pull up bar at the bottom. I would like both gone or at least to be rendering my app under them rather than having them as white bars top and bottom.
Any ideas?
Made a new issue here as this seems like a deep problem in MAUI for iOS with no solution on our end unless I am still missing something:
https://github.com/dotnet/maui/issues/17767
jonmdev setting that key to false with:
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
will work with my nuget package. If you can test setting to false it would be appreciated. I forgot to add that plist code to sample and info on package. That will be fixed soon. If your app can work with the key set to false my solution should work for you.
Thanks @ne0rrmatrix ne0rrmatrix, that does at least accomplish one thing: The status bar at the top text becomes invisible.
However, the status bar area (safe zone) is still occupying space with a white bar behind it and the home bar at the bottom are still present and both are stilling windowing the app top and bottom preventing full screen mode in iOS.
I found your code to do this is:
#if IOS || MACCATALYST
#pragma warning disable CA1422 // Validate platform compatibility
UIKit.UIApplication.SharedApplication.SetStatusBarHidden(shouldBeFullScreen, UIKit.UIStatusBarAnimation.Fade);
#pragma warning restore CA1422 // Validate platform compatibility
#endif
At least that is one step in the right direction.
Perhaps I also need a method to render into the safe zone? Maybe that is a separate issue? (ie. status bar is hidden but still being blocked from full screen by safe zone).
You can disable the safe area. Here is an example: https://learn.microsoft.com/en-us/dotnet/maui/ios/platform-specifics/page-safe-area-layout
Thanks @ne0rrmatrix ! That was perfect. I did not understand that method. For posterity, links explaining the methods are here:
https://learn.microsoft.com/en-us/dotnet/maui/ios/platform-specifics/page-safe-area-layout https://stackoverflow.com/questions/74724489/net-maui-ios-usesafearea-not-working-stacklayout-verticalstacklayout-and-grid https://learn.microsoft.com/en-us/xamarin/xamarin-forms/platform/ios/page-home-indicator
So to summarize for iOS, to get full screen, I did the following:
- Create page extensions to set page to full screen (as must be done on per page basis in iOS) and run this function on each page needing full screen:
using Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;
namespace MauiProject {
public static class PageExtensions {
public static void setPageToFullScreen(this Microsoft.Maui.Controls.Page page) {
page.On<Microsoft.Maui.Controls.PlatformConfiguration.iOS>().SetUseSafeArea(false);
page.On<Microsoft.Maui.Controls.PlatformConfiguration.iOS>().SetPrefersHomeIndicatorAutoHidden(true);
}
}
}
- In Info.plist add:
<key>UIStatusBarHidden</key>
<true/>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
- And in builder I took your method with the Pragmas to suppress the version warning exactly like this:
#if IOS
builder.ConfigureLifecycleEvents(events => {
events.AddiOS(iOs => {
iOs.OnActivated(activated => {
#pragma warning disable CA1422 // Validate platform compatibility
activated.SetStatusBarHidden(true, UIKit.UIStatusBarAnimation.None);
#pragma warning restore CA1422 // Validate platform compatibility
System.Diagnostics.Debug.WriteLine("IOS ACTIVATED");
});
});
});
#endif
- Set any layout objects to
layout.IgnoreSafeArea = true;
Then if one wants to lay out things manually based on safe zone in iOS one can use: On<iOS>().SafeAreaInsets();
to get the size.
Do you know of any way to get the safe zone size so easily in Android? Thanks again.
Hmm. My NuGet package does that but if you want to do it yourself you can copy the page extensions from either MS https://github.com/dotnet/maui/blob/main/src/Controls/src/Core/Platform/PageExtensions.cs or better copy mine and then you can get the current page:
static Page CurrentPage => GetCurrentPage(Application.Current?.MainPage ?? throw new InvalidOperationException($"{nameof(Application.Current.MainPage)} cannot be null."));
Just remove the PageExtensions.SetBarStatus(true) if your using MS one. Mine accounts for things like having a title and handles all the variable etc when needed. It is a rather tiresome complicated thing to get right. Out of the box this will not work in many situations for MS default page extension method. Using my extension and the code below it will work for android.
public void FullScreen()
{
PageExtensions.SetBarStatus(true);
var activity = Platform.CurrentActivity;
if (activity == null || activity.Window == null)
{
return;
}
Views.WindowCompat.SetDecorFitsSystemWindows(activity.Window, false);
var windowInsetsControllerCompat = Views.WindowCompat.GetInsetsController(activity.Window, activity.Window.DecorView);
var types = Views.WindowInsetsCompat.Type.StatusBars() |
Views.WindowInsetsCompat.Type.NavigationBars();
windowInsetsControllerCompat.SystemBarsBehavior = Views.WindowInsetsControllerCompat.BehaviorShowBarsBySwipe;
windowInsetsControllerCompat.Hide(types);
}
That sets full screen after page has loaded. It is near instant but does have a small animation fading the taskbar.