May 25, 2017

Force Landscape or Portrait for a single page in Xamarin Form.

Device screen orientation in xamarin is usually configured from Host(Android/iOS) project as suggested here . But what if i need to change the screen orientation of one particular screen(say to landscape) in xamarin form and other screens are different (may be portrait), to do so there is no direct options available from xamarin form.
We will do the configuration in host project for the common screen orientation required throughout the application, to do any changes for particular screen need to touch back to the host project settings again because as of now there is no wrapper Form level API’s available. 

For example consider the scenario that my Form project contains the Five screens out of that, for Third screen i need give support for both Portrait and Landscape and for all other remaining screen only in portrait. This can be done in android as follows,

Use the MessageCenter class to send the message from the Form screen for which orientation need to be changed and receive the same from Android MainActivity class.

ThirdPage.xamal.cs
  public partial class ThirdPage : ContentPage
    {
        protected override void OnAppearing()
        { 
            base.OnAppearing(); 
           MessagingCenter.Send(this, "allowLandScapePortrait”);
        }
         //during page close setting back to portrait
        protected override void OnDisappearing()
        {
            base.OnDisappearing(); 
            MessagingCenter.Send(this, "preventLandScape");
        }
    }

MainActivity.cs
[Activity(Label = "Main", ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,ScreenOrientation = ScreenOrientation.Portrait)]
 public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
  {        
  //allowing the device to change the screen orientation based on the rotation
  MessagingCenter.Subscribe<ThirdPage>(this, "allowLandScapePortrait", sender =>
  { 
   RequestedOrientation = ScreenOrientation.Unspecified;
  });

 //during page close setting back to portrait
 MessagingCenter.Subscribe<ThirdPage>(this, "preventLandScape", sender =>
  { 
   RequestedOrientation = ScreenOrientation.Portrait;
  });
 }
Activity class should contain the activity specifier, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation and default screen orientation is set as Portrait(ScreenOrientation = ScreenOrientation.Portrait). 

Note the important point here if the ScreenOrientation is set explicitly then you can’t rotate the any of the further screens. OnConfigurationChanged event won’t be called. Whenever i need to support both orientation just i mark the ScreenOrientation as Unspecified by passing the message from that screen. 

Same approach can be used for iOS application also. Alternative from iOS we can configure using AppDelegate and Custom renderer as follows,
//AppDelegate.cs
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations(UIApplication application,UIWindow forWindow)
{ 
   var mainPage = Xamarin.Forms.Application.Current.MainPage;
   if (mainPage.Navigation.NavigationStack.Last() is ThirdPage)
    {
    return UIInterfaceOrientationMask.AllButUpsideDown;
    }
  return UIInterfaceOrientationMask.Portrait;
}
Set Configuration back to portrait on page disappear.
//ThirdPageRenderer.cs
using System;
using Foundation; 
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(ThirdPage), typeof(ThirdPageRenderer))]
namespace MyForm.iOS
{
  public class ThirdPageRenderer : PageRenderer
  { 
    public override void ViewWillDisappear(bool animated)
     {
     base.ViewWillDisappear(animated);
     UIDevice.CurrentDevice.SetValueForKey(NSNumber.FromNInt((int)(UIInterfaceOrientation.Portrait)), new NSString("orientation")); 
     }
   }
}

This is all about changing the screen orientation in xamarin form  at runtime, Visit back here for the more exciting stuffs in mobile application development.