简体   繁体   中英

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? and I'm having trouble with it.

I override the OnConfigurationChanged method in MainActivity

        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. The XLabs documentation lists this as 'protected set', as does the compiler:

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?

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.

            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:

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). 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.

My PageBase has two abstract methods (so the children of it have to fill it in), which are UpdateLandscape and 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. I made PageBase override it and make it call UpdateLandscape and UpdatePortait accordingly.

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.


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).

On Android, I filled in my Android code as so:

[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:

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:

[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;

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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