Forum Xamarin.Forms

iOS - Restrict Page Orientation

SturgmeisterSturgmeister USUniversity ✭✭
edited June 2014 in Xamarin.Forms

I am working with Xamarin Forms and have an application with a few pages which I want to restrict the allowed orientations. So for example, on my first page (let's call it the home page), I want to only allow landscape orientation. On another page (let's say the image gallery), I want to allow any orientation. I have found out how to globally set allowed orientations, but when I navigate between pages with different allowed orientations, the page will continue rendering however the device is turned, instead of honoring the restriction. I am not very familiar with iOS, but I believe that native and mono applications allow this behavior.

I have set up my parent UIViewController to allow me to configure which orientations are returned through GetSupportedInterfaceOrientations, and that method is invoked every time the a new page is pushed or popped. I read here that presenting a new 'dummy' UIViewController in native would force the orientation change, because it will honor the supported orientations of that new UIViewController. Unfortunately, that does not seem to be working either. Note that neither navigating forward nor backward seem to work as desired.

My custom UIViewController hierarchy parent:

public partial class AppDelegate : UIApplicationDelegate
    {
        // class-level declarations
        UIWindow window;

        //
        // This method is invoked when the application has loaded and is ready to run. In this 
        // method you should instantiate the window, load the UI into it and then make the window
        // visible.
        //
        // You have 17 seconds to return from this method, or iOS will terminate your application.
        //
        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            Forms.Init();
            Xamarin.FormsMaps.Init();
            window = new UIWindow(UIScreen.MainScreen.Bounds);
            window.RootViewController = new FormsViewControllerWrapper(App.GetMainPage().CreateViewController());
            window.MakeKeyAndVisible();

            return true;
        }

        public override void FinishedLaunching(MonoTouch.UIKit.UIApplication application)
        {
            base.FinishedLaunching(application);

            UIDevice.CurrentDevice.BeginGeneratingDeviceOrientationNotifications();
        }
    }

    public class LandscapeViewController : UIViewController
    {
        public override MonoTouch.UIKit.UIInterfaceOrientationMask GetSupportedInterfaceOrientations()
        {
            return MonoTouch.UIKit.UIInterfaceOrientationMask.Landscape;
        }

        public override MonoTouch.UIKit.UIInterfaceOrientation PreferredInterfaceOrientationForPresentation()
        {
            return MonoTouch.UIKit.UIInterfaceOrientation.LandscapeLeft;
        }
    }

    public class FormsViewControllerWrapper : UIViewController
    {
        public static FormsViewControllerWrapper Instance { get; set; }
        public UIInterfaceOrientationMask AllowedOrientations { get; set; }

        public void ForceOrientationUpdate()
        {
            var dummyController = new LandscapeViewController();
            this.PresentViewController(dummyController, false, () => { });
            dummyController.DismissViewController(false, () => { });
        }

        public override MonoTouch.UIKit.UIInterfaceOrientationMask GetSupportedInterfaceOrientations()
        {
            return AllowedOrientations;
        }

        public override MonoTouch.UIKit.UIInterfaceOrientation PreferredInterfaceOrientationForPresentation()
        {
            return UIInterfaceOrientation.LandscapeLeft;
        }

        public override bool ShouldAutorotate()
        {
            return true;
        }

        public override bool ShouldAutomaticallyForwardRotationMethods
        {
            get 
            { 
                 return false;
            }
        }

        public FormsViewControllerWrapper(UIViewController child)
        {
            Instance = this;
            AllowedOrientations = UIInterfaceOrientationMask.Landscape;
            this.AddChildViewController(child);
            this.View.AddSubview(child.View);
        }
    }

The ForceOrientationUpdate method is what I'm calling whenever the device orientation does not agree with the required orientation for the page being displayed. So if the current page is in portrait mode, but the upcoming page can only be displayed in Landscape, I will update the AllowedOrientations, and call ForceOrientationUpdate. If this strategy will not work, or if you know of a better one, I want to hear about it! Thanks!

Best Answer

Answers

Sign In or Register to comment.