简体   繁体   English

如何在 Xamarin.Forms/XLabs 中处理屏幕旋转/方向?

[英]How to handle screen rotation/orientation in Xamarin.Forms/XLabs?

I'm trying to determine when a screen is rotated (in Android) using the XLabs method detailed here How to handle screen rotation/orientation in Xamarin Forms?我正在尝试使用此处详述的 XLabs 方法确定屏幕何时旋转(在 Android 中) How to handle screen rotation/orientation in Xamarin Forms? and I'm having trouble with it.我遇到了麻烦。

I override the OnConfigurationChanged method in MainActivity我覆盖了MainActivity 中OnConfigurationChanged方法

        public override void OnConfigurationChanged (Android.Content.Res.Configuration newConfig)
    {
        base.OnConfigurationChanged (newConfig);

        var xapp = Resolver.Resolve<IXFormsApp> ();
        if (xapp == null)
            return;

        switch (newConfig.Orientation) {
        case Android.Content.Res.Orientation.Landscape:
            xapp.Orientation = XLabs.Enums.Orientation.Landscape;
            break;
        case Android.Content.Res.Orientation.Portrait:
            //xapp.Orientation = XLabs.Enums.Orientation.Portrait;
            break;
        default:
            break;
        }
        }

I'm having trouble with the Orientation variable in IXFormsApp ie xapp.Orientation.我在使用 IXFormsApp 中的 Orientation 变量时遇到问题,即 xapp.Orientation。 The XLabs documentation lists this as 'protected set', as does the compiler: XLabs 文档将其列为“受保护集”,编译器也是如此:

MainActivity.cs(109,5,109,21): error CS0200: Property or indexer 'XLabs.Platform.Mvvm.IXFormsApp.Orientation' cannot be assigned to -- it is read only

and it doesn't get set automagically (when I check where it is used, it is always set to 'None'), so I was wondering how to make use of it, and indeed, how to use the XLabs/IXFormsApp to determine rotation?它不会自动设置(当我检查它的使用位置时,它总是设置为“无”),所以我想知道如何使用它,实际上,如何使用 XLabs/IXFormsApp 来确定回转?

On a related note, I was also trying to set the Rotation handler (not sure why, but I thought I'd give it a go) with unusual results.在相关说明中,我还试图设置 Rotation 处理程序(不知道为什么,但我想我会试一试),结果不寻常。

            xapp.Rotation += (sender, args) =>
        {
            switch (args.Value)
            {
            case XLabs.Enums.Orientation.Landscape:
                //xapp.Orientation = XLabs.Enums.Orientation.Landscape;
                ...
                break;
            case XLabs.Enums.Orientation.Portrait:
                ...
                break;
            default:
                break;
            }
            };

If I try in the Android code I get the following error:如果我在 Android 代码中尝试,我会收到以下错误:

MainActivity.cs(60,4,60,22): error CS0019: Operator '+=' cannot be applied to operands of type 'System.EventHandler<XLabs.EventArgs<XLabs.Enums.Orientation>>' and 'lambda expression'

however, if I set it in the Forms code (where the results are used), it is fine (altho the handler never seems to actually be called).但是,如果我在 Forms 代码(使用结果的地方)中设置它,那就没问题了(尽管处理程序似乎从未真正被调用过)。 Does anyone know whay this would be the case?有谁知道为什么会这样?

There are two different solutions I have used in the past.我过去使用过两种不同的解决方案。


The first is by making a PageBase class which all my pages inherit from, and PageBase inherits from a regular Page.第一种方法是创建一个 PageBase 类,我的所有页面都继承自该类,而 PageBase 继承自常规 Page。

My PageBase has two abstract methods (so the children of it have to fill it in), which are UpdateLandscape and UpdatePortait.我的 PageBase 有两个抽象方法(所以它的孩子必须填写它),它们是 UpdateLandscape 和 UpdatePortait。 Children will fill these methods in for how to layout the page depending on whether it is being laid out in landscape or portrait mode.孩子们将根据页面是以横向还是纵向模式布局来填写如何布局页面的这些方法。

Pages have a method OnSizeAllocated, as Daniel said.正如丹尼尔所说,页面有一个 OnSizeAllocated 方法。 I made PageBase override it and make it call UpdateLandscape and UpdatePortait accordingly.我让 PageBase 覆盖它并让它相应地调用 UpdateLandscape 和 UpdatePortait。

If, as you said, you are only looking to check when it has rotated, the above works just fine, as OnSizeAllocated gets called for a page whenever you rotate your phone.如果,如您所说,您只想检查它何时旋转,那么上面的方法就可以了,因为每当您旋转手机时,都会调用 OnSizeAllocated 页面。


If you are checking for landscape vs portait because you want your code to be able to check at any time, then the second solution below works too.如果您正在检查横向与纵向,因为您希望您的代码能够随时检查,那么下面的第二个解决方案也适用。

The second way I solved it is to use dependency services to fill in an IDeviceInfo interface, and write all dynamic things by checking if DeviceInfo.IsPortait() is true or false (and this way I also let DeviceInfo have a Width and Height, so I can request the screen dimensions at any point).我解决的第二种方法是使用依赖服务来填充一个 IDeviceInfo 接口,并通过检查 DeviceInfo.IsPortait() 是 true 还是 false 来编写所有动态的东西(这样我也让 DeviceInfo 有一个 Width 和 Height,所以我可以随时要求屏幕尺寸)。

On Android, I filled in my Android code as so:在 Android 上,我填写了我的 Android 代码,如下所示:

[assembly: Dependency (typeof(Namespace.DeviceInfoProvider))]
namespace Namespace
{
  public class DeviceInfoProvider : IDeviceInfoProvider
  {
    public bool IsPortait () { return DeviceInfoManager.Width < DeviceInfoManager.Height; }
    public int GetWidth () {  return DeviceInfoManager.Width; }
    public int GetHeight () { return DeviceInfoManager.Height; }
  }

  public static class DeviceInfoManager
  {
    public static MainActivity MainActivity { get; set; }
    public static int Width { get { return MainActivity.GetWidth (); } }
    public static int Height { get { return MainActivity.GetHeight (); } }
  }
}

Then in MainActivity I gave it these methods:然后在 MainActivity 中我给了它这些方法:

public int GetWidth() {
      return (int)(Resources.DisplayMetrics.WidthPixels / Resources.DisplayMetrics.Density);
    }

    public int GetHeight() {
      return (int)(Resources.DisplayMetrics.HeightPixels / Resources.DisplayMetrics.Density);
    }

And on the iOS side, I filled it in as so:在 iOS 方面,我是这样填写的:

[assembly: Dependency (typeof(Namespace.DeviceInfoProvider))]
namespace Namespace {

  public class DeviceInfoProvider : IDeviceInfoProvider {
    public bool IsPortait() { return UIScreen.MainScreen.Bounds.Width < UIScreen.MainScreen.Bounds.Height; }

    public int GetWidth() { return (int)UIScreen.MainScreen.Bounds.Width; }

    public int GetHeight() { return (int)UIScreen.MainScreen.Bounds.Height; }
  }
}

Personally, I am more of a fan of writing it the second way and making it check "if we are in portait mode, here are the differences".就个人而言,我更喜欢以第二种方式编写它并检查“如果我们处于肖像模式,这里是差异”。 That way those things that are not different between portait and landscape only have to be written once, only the differences are written twice.这样,那些在肖像和风景之间没有区别的东西只需写一次,只有不同之处才写两次。

You can use OnSizeAllocated method override to detect orientation change;您可以使用 OnSizeAllocated 方法覆盖来检测方向变化;

double previousWidth;
double previousHeight;

    protected override void OnSizeAllocated(double width, double height)
    {
        base.OnSizeAllocated(width, height);

        if (previousWidth != width || previousHeight != height)
        {
            previousWidth = width;
            previousHeight = height;

            if (width > height)
            {
                // landscape mode
            }
            else
            {
                // portrait mode
            }   
        }
    }

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

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