使用Xamarin.Forms / Xamarin.Droid具有稳定布局的可切换全屏

时间:2019-06-13 12:21:42

标签: c# android xamarin.forms xamarin.droid

我正在制作一个必须能够在两种视图模式之间切换的应用程序:

  • 全屏:视图应显示在整个屏幕上,没有标题栏/导航栏/操作栏。
  • 半全屏:视图仍应填满整个屏幕,但标题/导航/操作栏现在应该出现在视图的前面,而根本不调整视图的大小。

为了测试在这两种模式之间切换的行为,我创建了一个简单的测试项目,该项目每两秒钟在这两种模式之间进行切换。

全屏模式按预期工作,但是半全屏模式存在两个问题,如下图所示:

  1. 将视图内容(带有五个文本行的Label)下推。我希望它保留在屏幕顶部,部分隐藏在系统栏的后面。
  2. 操作栏显示在状态栏的后面。我希望它显示在状态栏下方。

为了获得所需的行为,我需要更改什么? (我认为必须在Page1.xaml.cs或MainActivity.cs中的ToggleFullscreen函数中进行更改)

enter image description here

我的代码如下:

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

1 个答案:

答案 0 :(得分:0)

您可以在Y offset时添加stackLayout中的isFullScreen = false。例如,在stackLayout和后面的代码中为Xaml命名:

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

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

        NavigationPage.SetHasNavigationBar(this, !isFullscreen);

    });
}

然后在您的MainActivity中,在SystemUiFlags.LayoutHideNavigation ,SystemUiFlags.LayoutFullscreen时删除isFullScreen = 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
            );
        }
    });
}

我已经上传了一个样本,您可以检查:toggle-model-xamarin.forms

  

在我的手机上,偏移量必须为-74-有一种可靠的方法   确定从手机到手机?

您可以通过获取status baraction bar的高度来获取偏移量:使用dependency service首先获取高度,然后设置偏移量,您可以查看此线程android-status-bar-height-in-xamarin-android

  

重新定位时,设计仍会闪烁-没办法   完全避免重新定位?

不知道闪光灯,似乎一一显示了视图。

  

我没有提到视图包含应该保留的元素   在屏幕的底部边缘,使用TranslateY时,这些是   也向上移动

在这种情况下,您只能将偏移量设置为要更改的视图,而不是整个视图。