So the title says it all. Im concerned at this point with iOS. I have tried to sue a custom renderer for my base page "LandscapeContentPage" which would hopefully force it to be rendered as landscape. I have been unsuccessful.
I attempted to use a hack I found where in ViewDidAppear you present a "fake" UIViewController that overrides the GetSupportedInterfaceOrientations to only return Landscape. This sort of works. The meat looks like this:
var c = new LandscapeViewController();
c.View.BackgroundColor = UIColor.Cyan;
await PresentViewControllerAsync(c, false);
await DismissViewControllerAsync(false);
If I set a breakpoint at the Dismiss line I can see in the simulator that the view did change to landscape, the simulator window actually rotates on its own. When I continue either an error is thrown about view transitions or the ViewDidAppear fires again and the original page is displayed in portrait orientation.
So, I'm more or less lost at this point. I have tried so many different things and had zero success. I can't figure out why there isn't an out of the box mechanism for this. Such an expensive toolset/framework seems incomplete without orientation handling.
Thanks.
Xamarin. Android supports several options for specifying orientation: Landscape – forces the application orientation to be landscape, regardless of sensor data. Portrait – forces the application orientation to be portrait, regardless of sensor data.
Change part of a document to landscape Select the content that you want on a landscape page. Go to Layout, and open the Page Setup dialog box. Select Landscape, and in the Apply to box, choose Selected text.
The approach from Chad Bonthuys works like a charms. I've got two litte additions.
Android: If you rotate and leave the view, the other views now will be in the requested orientation as well. Just call
GetActivity().RequestedOrientation = ScreenOrientation.Unspecified;
on leaving. That will allow other views to rotate again.
iOS: The view will be rotated, but the user is still able to rotate it back. You can lock it if you override the
GetSupportedInterfaceOrientations()
on
AppDelegate.cs
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations (UIApplication application, [Transient] UIWindow forWindow)
{
if (Xamarin.Forms.Application.Current == null || Xamarin.Forms.Application.Current.MainPage == null)
{
return UIInterfaceOrientationMask.All;
}
var mainPage = Xamarin.Forms.Application.Current.MainPage;
if (mainPage is YOUR_VIEW||
(mainPage is NavigationPage && ((NavigationPage)mainPage).CurrentPage is YOUR_VIEW) ||
(mainPage.Navigation != null && mainPage.Navigation.ModalStack.LastOrDefault () is YOUR_VIEW))
{
return UIInterfaceOrientationMask.Landscape;
}
return UIInterfaceOrientationMask.All;
}
Just replace YOUR_VIEW with your ContentPage you want to lock
I used a dependency service for this.
https://developer.xamarin.com/guides/cross-platform/xamarin-forms/dependency-service/
public interface IOrientationHandler
{
void ForceLandscape();
void ForcePortrait();
}
DependencyService.Get<IOrientationHandler>().ForceLandscape();
public class OrientationHandlerImplementation : IOrientationHandler
{
public void ForceLandscape()
{
UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)UIInterfaceOrientation.LandscapeLeft), new NSString("orientation"));
}
public void ForcePortrait()
{
UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)UIInterfaceOrientation.Portrait), new NSString("orientation"));
}
}
public class OrientationHandler : BaseDependencyImplementation, IOrientationHandler
{
public void ForceLandscape()
{
GetActivity().RequestedOrientation = ScreenOrientation.Landscape;
}
public void ForcePortrait()
{
GetActivity().RequestedOrientation = ScreenOrientation.Portrait;
}
}
Edit - Added Base Dependency Implementation as per request
public class BaseDependencyImplementation : Object
{
public Activity GetActivity()
{
var activity = (Activity)Forms.Context;
return activity;
}
}
If you want to set orientation for the whole app it can be done in the app settings / manifest file.
The below solution works with out dependency service.
Suppose if we want to have three pages and for second page only we need to have landscape orientation, below code is working for me.
Add below method to AppDelegate.cs
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations(UIApplication application, [Transient] UIWindow forWindow)
{
if (Xamarin.Forms.Application.Current == null || Xamarin.Forms.Application.Current.MainPage == null)
{
return UIInterfaceOrientationMask.Portrait;
}
var mainPage = Xamarin.Forms.Application.Current.MainPage;
if (mainPage is SecondPage ||
(mainPage is NavigationPage && ((NavigationPage)mainPage).CurrentPage is SecondPage) ||
(mainPage.Navigation != null && mainPage.Navigation.ModalStack.LastOrDefault() is SecondPage))
{
return UIInterfaceOrientationMask.Landscape;
}
return UIInterfaceOrientationMask.Portrait;
}
Add a custom renderer to change the orientation.
[assembly: ExportRenderer(typeof(MainPage), typeof(MainPagePageRenderer))]
namespace App2.iOS
{
public class MainPagePageRenderer : PageRenderer
{
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
UIDevice.CurrentDevice.SetValueForKey(NSNumber.FromNInt((int)(UIInterfaceOrientation.LandscapeLeft)), new NSString("orientation"));
}
}
}
Here, we have three pages MainPage, SecondPage and ThirdPage in the app and we are trying to fix landscape orientation to SecondPage. We need to create a custom renderer for MainPage since we need to change the orientation when going to SecondPage. We fix the orientation in AppDelegate for SecondPage so it won't change the orientation even if we rotate the phone.
Now, the portrait orientation is locked for MainPage and ThirdPage and the landscape for SecondPage.
We may need to create as many as custom renderers for each page to fix orientation.
Thanks.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With