I'm making an app that must be able to toggle between two view modes:
- Fullscreen: the view should show on the entire screen, with no title bar/navigation bar/action bar.
- Semi-fullscreen: the view should still fill the entire screen, but title/navigation/action bars should now appear in front of the view, without resizing the view at all.
To test the behaviour of toggling between these two modes, I have created a simple test project that switches between these two modes every two seconds.
The fullscreen mode is working as intended, but there are two issues with the semi-fullscreen mode, as shown in the images below:
- The view contents (the Label with five text lines) is pushed down. I want it to remain at the top of the screen, partially hidden behind the system bars.
- The action bar is shown behind the status bar. I want it to be shown below the status bar.
What do I need to change in order to get the behaviour I want? (I assume the changes must be made in the ToggleFullscreen function in Page1.xaml.cs or MainActivity.cs)
My code looks like this:
App.xaml.cs
using System;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace ActionBarTest
{
public partial class App : Application
{
public App()
{
InitializeComponent();
var np = new NavigationPage(new Page1());
np.Title = "ActionBarTest";
MainPage = np;
}
}
}
Page1.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="ActionBarTest.Page1">
<ContentPage.Content>
<StackLayout>
<Label Text="Welcome to Xamarin.Forms!"
VerticalOptions="Start"
HorizontalOptions="CenterAndExpand" />
<Label Text="Line one"
VerticalOptions="Start"
HorizontalOptions="CenterAndExpand" />
<Label Text="Line two"
VerticalOptions="Start"
HorizontalOptions="CenterAndExpand" />
<Label Text="Line three"
VerticalOptions="Start"
HorizontalOptions="CenterAndExpand" />
<Label Text="Line four"
VerticalOptions="Start"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
Page1.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace ActionBarTest
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Page1 : ContentPage
{
public Page1()
{
InitializeComponent();
Task.Factory.StartNew(() => {
while (true)
{
Thread.Sleep(2000);
ToggleFullscreen(true);
Thread.Sleep(2000);
ToggleFullscreen(false);
}
});
}
}
private void ToggleFullscreen(bool isFullscreen){
Xamarin.Forms.Device.BeginInvokeOnMainThread(() => { NavigationPage.SetHasNavigationBar(this, !isFullscreen); });
}
}
MainActivity.cs
using System;
using System.Threading;
using Android.App;
using Android.Content.PM;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
namespace ActionBarTest.Droid
{
[Activity(Label = "ActionBarTest", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
System.Threading.Tasks.Task.Factory.StartNew(() => {
while (true)
{
Thread.Sleep(2000);
ToggleFullscreen(true);
Thread.Sleep(2000);
ToggleFullscreen(false);
}
});
}
private void ToggleFullscreen(bool isFullscreen)
{
RunOnUiThread(() =>
{
if (isFullscreen)
{
Window.DecorView.SystemUiVisibility = (StatusBarVisibility)(
SystemUiFlags.Fullscreen
| SystemUiFlags.HideNavigation
| SystemUiFlags.Immersive
| SystemUiFlags.ImmersiveSticky
| SystemUiFlags.LowProfile
| SystemUiFlags.LayoutStable
| SystemUiFlags.LayoutHideNavigation
| SystemUiFlags.LayoutFullscreen
);
}
else
{
Window.DecorView.SystemUiVisibility = (StatusBarVisibility)(
SystemUiFlags.LayoutStable
| SystemUiFlags.LayoutHideNavigation
| SystemUiFlags.LayoutFullscreen
);
}
});
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}

You can add a
Y offsetofstackLayoutwhenisFullScreen = false. For example, give a name tostackLayoutinXamland in the code behiend:And in your MainActivity, remove the
SystemUiFlags.LayoutHideNavigation ,SystemUiFlags.LayoutFullscreenwhenisFullScreen = false:I have uploaded a sample and you can check: toggle-model-xamarin.forms
You can get the offset by getting the height of
status barandaction bar: use a dependency service to get the height first and then set the offset, you can look at this thread about android-status-bar-height-in-xamarin-android.No idea about the flashes, it seems show the view one by one.
Under this situation, you can only set the offset to the view you want to change instead of the whole view.