简体   繁体   English

使用Xamarin.Forms / Xamarin.Droid进行可切换全屏,稳定布局

[英]Toggleable fullscreen with stable layout using Xamarin.Forms/Xamarin.Droid

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: 全屏模式按预期工作,但半全屏模式存在两个问题,如下图所示:

  1. The view contents (the Label with five text lines) is pushed down. 按下视图内容(带有五个文本行的Label)。 I want it to remain at the top of the screen, partially hidden behind the system bars. 我希望它保留在屏幕的顶部,部分隐藏在系统栏后面。
  2. 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) (我假设必须在Page1.xaml.cs或MainActivity.cs中的ToggleFullscreen函数中进行更改)

在此输入图像描述

My code looks like this: 我的代码看起来像这样:

App.xaml.cs 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 的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 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 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 offset of stackLayout when isFullScreen = false . isFullScreen = false时,您可以添加stackLayoutY offset For example, give a name to stackLayout in Xaml and in the code behiend: 例如,提供一个名称stackLayoutXaml ,并在代码behiend:

private void ToggleFullscreen(bool isFullscreen)
{
    Xamarin.Forms.Device.BeginInvokeOnMainThread(() => {

        if (isFullscreen)
        {
            myStackLayout.TranslationY = 0;
        }
        else
        {
            myStackLayout.TranslationY = -64;
        }

        NavigationPage.SetHasNavigationBar(this, !isFullscreen);

    });
}

And in your MainActivity, remove the SystemUiFlags.LayoutHideNavigation ,SystemUiFlags.LayoutFullscreen when isFullScreen = false : 在MainActivity中,当isFullScreen = false时,删除SystemUiFlags.LayoutHideNavigation ,SystemUiFlags.LayoutFullscreen

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

I have uploaded a sample and you can check: toggle-model-xamarin.forms 我上传了一个样本,您可以查看: toggle-model-xamarin.forms

on my phone, the offset had to be -74 -- is there a way of reliably determining it from phone to phone? 在我的手机上,偏移量必须是-74 - 有没有办法从手机到手机可靠地确定它?

You can get the offset by getting the height of status bar and action 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 . 您可以通过获取status baraction bar的高度来获得偏移:使用依赖服务首先获取高度然后设置偏移量,您可以查看关于android-status-bar-height-in-xamarin-的此主题安卓

The design still flashes while it is repositioned -- is there no way of avoiding a reposition at all? 设计在重新定位时仍然闪烁 - 是否根本无法避免重新定位?

No idea about the flashes, it seems show the view one by one. 不知道闪光,似乎逐一显示视图。

I didn't mention that the view has elements that are supposed to stay at the bottom edge of the screen, and when using TranslateY, these are moved upwards as well 我没有提到视图中的元素应该保留在屏幕的下边缘,当使用TranslateY时,这些元素也会向上移动

Under this situation, you can only set the offset to the view you want to change instead of the whole view. 在这种情况下,您只能将偏移设置为要更改的视图而不是整个视图。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM