【问题标题】:Toggleable fullscreen with stable layout using Xamarin.Forms/Xamarin.Droid使用 Xamarin.Forms/Xamarin.Droid 具有稳定布局的可切换全屏
【发布时间】:2019-06-14 16:25:57
【问题描述】:

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

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

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

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

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

为了获得我想要的行为,我需要进行哪些更改? (我假设必须在 Page1.xaml.cs 或 MainActivity.cs 的 ToggleFullscreen 函数中进行更改)

我的代码如下所示:

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

【问题讨论】:

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


    【解决方案1】:

    isFullScreen = false 时,您可以添加Y offsetstackLayout。例如,在Xaml 和隐藏代码中为stackLayout 命名:

    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 when 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 时,这些是 也向上移动

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

    【讨论】:

    • 谢谢!虽然这可行,但它存在一些问题。 1)在我的手机上,偏移量必须是-74——有没有办法可靠地确定手机之间的偏移量? 2)设计在重新定位时仍然闪烁 - 根本没有办法避免重新定位吗? 3) 抱歉,我没有提到视图中的元素应该留在屏幕的底部边缘,并且在使用 TranslateY 时,这些元素也会向上移动——有没有办法解决这个问题?
    • 好的,再次感谢!如果有办法将页面内容保留在栏的“后面”,而完全不更改任何布局,那么最好的方法当然是,但如果这不可能,这是一个有效的解决方法,虽然有点骇人听闻。很高兴看到 MSFT 团队前来救援!
    猜你喜欢
    • 1970-01-01
    • 2018-05-24
    • 1970-01-01
    • 2014-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-30
    • 1970-01-01
    相关资源
    最近更新 更多