使用适用于 Android 但不适用于 iOS 的多目标功能将特定 MAUI 视图强制为横向定向

问题描述 投票:0回答:2

我需要一个特定的 MAUI 页面以仅横向显示。 我找到了这个关于强制设备方向的tutorial,我正在使用 MAUI 的多目标功能来实现强制此方向所需的设备特定代码。教程说他们没有测试 iOS 版本。 我有适用于 Android 的教程(允许通过单例服务以编程方式强制单个页面的横向方向)但不适用于 iOS。

using System;
namespace ScoreKeepersBoard.DeviceServices;

public partial class DeviceOrientationService : IDeviceOrientationService
{
    public partial void SetDeviceOrientation(DisplayOrientation displayOrientation);
}

这里是我将设备方向服务注入我的视图模型并将方向设置为横向的地方:

public partial class NewGameViewModel : ObservableObject
{
    IGameTypeDataAccess gameTypeDataAccess;
    ITeamDataAccess teamDataAccess;
    IDeviceOrientationService deviceOrientationService;

    [ObservableProperty]
    IList<GameType> gameTypes = new List<GameType>();

    [ObservableProperty]
    private GameType selectedGameType;

    [ObservableProperty]
    private string gameTypeSelectionError;

    [ObservableProperty]
    private ObservableCollection<Team> teamOneTeams = new ObservableCollection<Team>();

    [ObservableProperty]
    private Team teamOneSelection;

    [ObservableProperty]
    private string teamOneSelectionError;

    [ObservableProperty]
    private ObservableCollection<Team> teamTwoTeams = new ObservableCollection<Team>();

    [ObservableProperty]
    private Team teamTwoSelection;

    [ObservableProperty]
    private string teamTwoSelectionError;

    private ObservableCollection<Team> allTeams = new ObservableCollection<Team>();

    private bool react = true;

    public NewGameViewModel(IGameTypeDataAccess iGameTypeDataAccess, ITeamDataAccess iTeamDataAccess, IDeviceOrientationService iDeviceOrientationService)
    {
        gameTypeDataAccess = iGameTypeDataAccess;
        teamDataAccess = iTeamDataAccess;
        deviceOrientationService = iDeviceOrientationService;

        

        deviceOrientationService.SetDeviceOrientation(DisplayOrientation.Landscape);
    }
}

这是我在 /Platforms/Android 文件夹中的多目标代码:

using System;
using Android.Content.PM;

namespace ScoreKeepersBoard.DeviceServices;

public partial class DeviceOrientationService
{

    private static readonly IReadOnlyDictionary<DisplayOrientation, ScreenOrientation> _androidDisplayOrientationMap =
        new Dictionary<DisplayOrientation, ScreenOrientation>
        {
            [DisplayOrientation.Landscape] = ScreenOrientation.Landscape,
            [DisplayOrientation.Portrait] = ScreenOrientation.Portrait,
        };

    public partial void SetDeviceOrientation(DisplayOrientation displayOrientation)
    {
        var currentActivity = ActivityStateManager.Default.GetCurrentActivity();
        if(currentActivity is not null)
        {
            if(_androidDisplayOrientationMap.TryGetValue(displayOrientation, out ScreenOrientation screenOrientation))
            {
                currentActivity.RequestedOrientation = screenOrientation;
            }
        }
    }
}

我在 /Platforms/iOS 中有类似的多目标 iOS 设置。 更新:我根据 Dongzhi Wang-MSFT 的回答编辑了我的代码

using System;
using Foundation;
using UIKit;

namespace ScoreKeepersBoard.DeviceServices;

public partial class DeviceOrientationService
{

    private static readonly IReadOnlyDictionary<DisplayOrientation, UIInterfaceOrientation> _iosDisplayOrientationMap =
        new Dictionary<DisplayOrientation, UIInterfaceOrientation>
        {
            [DisplayOrientation.Landscape] = UIInterfaceOrientation.LandscapeLeft,
            [DisplayOrientation.Portrait] = UIInterfaceOrientation.Portrait,
        };

    public partial void SetDeviceOrientation(DisplayOrientation displayOrientation)
    {

        if (UIDevice.CurrentDevice.CheckSystemVersion(16, 0))
        {

            var scene = (UIApplication.SharedApplication.ConnectedScenes.ToArray()[0] as UIWindowScene);
            if (scene != null)
            {
                var uiAppplication = UIApplication.SharedApplication;
                var test = UIApplication.SharedApplication.KeyWindow?.RootViewController;
                if (test != null)
                {
                    test.SetNeedsUpdateOfSupportedInterfaceOrientations();
                    scene.RequestGeometryUpdate(
                        new UIWindowSceneGeometryPreferencesIOS(UIInterfaceOrientationMask.Portrait), error => { });
                }
            }
        }
        else
        {
            UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)UIInterfaceOrientation.Portrait), new NSString("orientation"));
        }


    }
}

这会强制方向为纵向,但是当我从纵向切换到横向时,布局首先切换到横向,然后强制进入纵向,如下面的 GIF 图像所示。

我怎样才能在用户改变方向时保持纵向?

更新: 我更新了我的 .NET MAUI,更新要求我使用 XCODE 14.2,现在我的虚拟模拟器都运行 iOS 16.2,现在 iOS 版本的代码根本不起作用,也不会将屏幕锁定到任何方向。 我现在在 iOS 平台特定代码中收到此警告:

对于 iOS 16.2 版,此解决方案似乎不再适用!

ios maui device-orientation
2个回答
0
投票

在Maui中,可以使用Invoke平台代码调用iOS原生API来实现。详情请参考官方文档:调用平台代码 |微软.

iOS部分代码:

if (UIDevice.CurrentDevice.CheckSystemVersion(16, 0))
            {
                var scene = (UIApplication.SharedApplication.ConnectedScenes.ToArray()[0] as UIWindowScene);
                if(scene != null)
                {
                    var test = UIApplication.SharedApplication.KeyWindow?.RootViewController;
                   if (test != null)
                    {
                        test.SetNeedsUpdateOfSupportedInterfaceOrientations();
                        scene.RequestGeometryUpdate(
                            new UIWindowSceneGeometryPreferencesIOS(UIInterfaceOrientationMask.Landscape), error => { });
                    }
                }
            }   
            else
            {
                UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)UIInterfaceOrientation.LandscapeLeft), new NSString("orientation"));
            }

0
投票

好吧,最后我在我的应用程序中这样做了。

我只想强制一个特定页面的方向,而不是所有页面,这就是为什么我改变了所有程序如下:

DeviceOrientationService.Android.cs

public partial class DeviceOrientationService
{
    private static readonly IReadOnlyDictionary<DisplayOrientation, ScreenOrientation> _androidDisplayOrientationMap =
        new Dictionary<DisplayOrientation, ScreenOrientation>
        {
            [DisplayOrientation.Landscape] = ScreenOrientation.Landscape,
            [DisplayOrientation.Portrait] = ScreenOrientation.Portrait,
        };

    public partial async Task SetDeviceOrientation(DisplayOrientation displayOrientation)
    {
        var currentActivity = ActivityStateManager.Default.GetCurrentActivity();
        if (currentActivity is not null)
        {
            if (_androidDisplayOrientationMap.TryGetValue(displayOrientation, out ScreenOrientation screenOrientation))
                currentActivity.RequestedOrientation = screenOrientation;
        }
        await Task.Delay(100);
    }
}

DeviceOrientationService.iOS.cs

public partial class DeviceOrientationService
{
    private static readonly IReadOnlyDictionary<DisplayOrientation, UIInterfaceOrientation> _iosDisplayOrientationMap =
        new Dictionary<DisplayOrientation, UIInterfaceOrientation>
        {
            [DisplayOrientation.Landscape] = UIInterfaceOrientation.LandscapeLeft,
            [DisplayOrientation.Portrait] = UIInterfaceOrientation.Portrait,
        };

    public partial async Task SetDeviceOrientation(DisplayOrientation displayOrientation)
    {
        if (_iosDisplayOrientationMap.TryGetValue(displayOrientation, out var iosOrientation))
        {
            if (UIDevice.CurrentDevice.CheckSystemVersion(16, 0))
            {
                var scene = (UIApplication.SharedApplication.ConnectedScenes.ToArray()[0] as UIWindowScene);
                if (scene != null)
                {
                    var uiAppplication = UIApplication.SharedApplication;
                    var test = UIApplication.SharedApplication.KeyWindow?.RootViewController;
                    if (test != null)
                    {
                        UIInterfaceOrientationMask NewOrientation;
                        if (iosOrientation == UIInterfaceOrientation.Portrait)
                        {
                            NewOrientation = UIInterfaceOrientationMask.Portrait;
                        }
                        else
                        {
                            NewOrientation = UIInterfaceOrientationMask.LandscapeLeft;
                        }
                        scene.Title = "PerformOrientation";
                        scene.RequestGeometryUpdate(
                            new UIWindowSceneGeometryPreferencesIOS(NewOrientation), error => { System.Diagnostics.Debug.WriteLine(error.ToString()); });
                        test.SetNeedsUpdateOfSupportedInterfaceOrientations();
                        test.NavigationController?.SetNeedsUpdateOfSupportedInterfaceOrientations();
                        await Task.Delay(1000); //Gives the time to apply the view rotation
                        scene.Title = "";
                    }
                }
            }
            else
            {
                UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)iosOrientation), new NSString("orientation"));
            }
        }
    }
}

非常重要,在AppDelegate.cs文件(/Platforms/iOS)中你应该添加:

[Export("application:supportedInterfaceOrientationsForWindow:")]
public UIInterfaceOrientationMask GetSupportedInterfaceOrientations(UIApplication application, UIWindow forWindow)
{
    if (forWindow.WindowScene != null && forWindow.WindowScene.Title == "PerformOrientation")
    {
        return UIInterfaceOrientationMask.All;
    }
    else
    {
        return application.SupportedInterfaceOrientationsForWindow(forWindow);
    }
}

一切都很好!此外,在您第一次强制定向后,如果设备旋转到不在 info.plist 中的方向,则不会发生定向。

© www.soinside.com 2019 - 2024. All rights reserved.