dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.17k stars 1.74k forks source link

Fullscreen #5478

Open Realgigabyte opened 2 years ago

Realgigabyte commented 2 years ago

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.

robertodalmonte commented 2 years ago

I'd really like to have that functionality too.

ghost commented 2 years ago

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.

arthurLNF commented 2 years ago

Has this feature been reconsidered or already being implemented?

SandroCODTEC commented 2 years ago

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.

ewerspej commented 2 years ago

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.

LahkLeKey commented 2 years ago

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>
Taiizor commented 2 years ago

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 (:

jasonmillernc99 commented 1 year ago

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

        }
    }

screen without box Screen with box

LahkLeKey commented 1 year ago

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

dimplevador commented 1 year ago

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
    }
}
Realgigabyte commented 1 year ago

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;

mouralabank commented 1 year ago

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.

jfversluis commented 1 year ago

@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 commented 1 year ago

@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!!!

ne0rrmatrix commented 1 year ago

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

Brionvega commented 1 year ago

@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!

dimplevador commented 1 year ago

@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
    }
Brionvega commented 1 year ago

@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 :)

xx7Ahmed7xx commented 1 year ago

@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 commented 1 year ago

@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 :)

Irasil commented 1 year ago

I need this for MacOS or rather a way how I can run a Maui app in the system tray of MacOS :)

ne0rrmatrix commented 1 year ago

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.

jonmdev commented 1 year ago

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?

jonmdev commented 1 year ago

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?

jonmdev commented 1 year ago

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

ne0rrmatrix commented 1 year ago

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.

jonmdev commented 1 year ago

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).

ne0rrmatrix commented 1 year ago

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

jonmdev commented 1 year ago

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:

1) 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);
        }
    }
}

2) In Info.plist add:

<key>UIStatusBarHidden</key>
<true/>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>

3) 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
  1. 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.

ne0rrmatrix commented 1 year ago

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.

jonmdev commented 1 year ago

Thanks. just to be clear, I was asking about how to get the safe zone inset sizes. I am already able to build into the safe zone and full screen Android using the method posted here which interestingly runs a bit differently than your strategy but accomplishes the same as yours and on immediate app build:

https://github.com/dotnet/maui/issues/5478#issuecomment-1742219379

I am able to also get iOS insets with the following which is working:

#if IOS
                UIKit.UIWindow window = UIKit.UIApplication.SharedApplication.Delegate.GetWindow();
                var bottomPadding = window.SafeAreaInsets.Bottom;
                var topPadding = window.SafeAreaInsets.Top;
                Debug.WriteLine("PAD BOTTOM " + bottomPadding + " TOP " + topPadding);
#endif

For Android, this seems to work on higher levels of Android but if there is no inset (no notch to cause safe zone) will not return correctly so must be protected against to return zero if objects don't exist:

var activity = Platform.CurrentActivity;
var insets = activity.Window.DecorView.RootView.RootWindowInsets;
var displaycutout = insets.DisplayCutout;
var corrected = this.ToPlatform(this.Handler.MauiContext).Context.FromPixels(displaycutout.SafeInsetTop);
Debug.WriteLine("ANDROID INSETS TOP " + displaycutout.SafeInsetTop + " BOT " + displaycutout.SafeInsetBottom + " CORRECTED " + corrected);

Thanks again for your help. Happy to have it all working.

ne0rrmatrix commented 1 year ago

An update for Android full screen to get rid of obsolete method call in dotnet 8.

Restore Screen

   var activity = Platform.CurrentActivity;

   if (activity == null || activity.Window == null)
   {
       return;
   }

   Views.WindowCompat.SetDecorFitsSystemWindows(activity.Window, true);
   var windowInsetsControllerCompat = Views.WindowCompat.GetInsetsController(activity.Window, activity.Window.DecorView);
   var types = Views.WindowInsetsCompat.Type.StatusBars() |
               Views.WindowInsetsCompat.Type.NavigationBars();
   windowInsetsControllerCompat.Show(types);
   windowInsetsControllerCompat.SystemBarsBehavior = Views.WindowInsetsControllerCompat.BehaviorDefault;

Full Screen

  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.BehaviorShowTransientBarsBySwipe;
  windowInsetsControllerCompat.Hide(types);

The key changes are

neonleo commented 11 months ago

MAUI definitely far from production use, full screen is simple few line of code to make it works on Android or React Native, but .NET 8.0 MAUI still missing of it And thanks ne0rrmatrix make a Nuget package to make it happen.

fe56 commented 10 months ago

I encountered the same issue. A workaround on Android for me was using this OnCreate method:

    protected override void OnCreate(Bundle? savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        Platform.Init(this, savedInstanceState);
        IWindowInsetsController wicController = Window.InsetsController;
        Window.SetDecorFitsSystemWindows(false);
        Window.SetFlags(WindowManagerFlags.Fullscreen, WindowManagerFlags.Fullscreen);
        if (wicController != null)
        {
            wicController.Hide(WindowInsets.Type.SystemBars());
        }
    }
Yu-Core commented 5 months ago

For me, the best way is on Android

        protected override void OnCreate(Bundle savedInstanceState)
        {
            Google.Android.Material.Internal.EdgeToEdgeUtils.ApplyEdgeToEdge(Window, true);
            if (OperatingSystem.IsAndroidVersionAtLeast((int)BuildVersionCodes.Q))
            {
                Window.StatusBarContrastEnforced = false;
                Window.NavigationBarContrastEnforced = false;
            }

            base.OnCreate(savedInstanceState);
        }