gioma 19 Posted October 3, 2019 Hi, I need to rotate the screen at runtime when I open a form. Until the release of IOS 13 this code worked perfectly: procedure ChangeOrientation(toOrientation: UIInterfaceOrientation; possibleOrientations: TScreenOrientations); var win : UIWindow; App : UIApplication; viewController : UIViewController; oucon: UIViewController; begin Application.FormFactor.Orientations := []; //Change supported orientations App := TUIApplication.Wrap(TUIApplication.OCClass.sharedApplication); win := TUIWindow.Wrap(App.windows.objectAtIndex(0)); //The first Windows is always the main Window App.setStatusBarOrientation(toOrientation); {After you have changed your statusbar orientation set the Supported orientation/orientations to whatever you need} Application.FormFactor.Orientations := possibleOrientations; viewController := TUIViewController.Wrap(TUIViewController.alloc.init);//dummy ViewController oucon := TUIViewController.Wrap(TUIViewController.alloc.init); {Now we are creating a new Viewcontroller now when it is created it will have to check what is the supported orientations} oucon := win.rootViewController;//we store all our current content to the new ViewController Win.setRootViewController(viewController); Win.makeKeyAndVisible;// We display the Dummy viewcontroller win.setRootViewController(oucon); win.makeKeyAndVisible; {And now we Display our original Content in a new Viewcontroller with our new Supported orientations} end; However, since the release of IOS 13 the screen locks on the set orientation but does not rotate. So if I set Landscape orientation the screen remains in Portrait orientation until I physically turn the phone around, at which point it rightly remains locked on that orientation. This is a real disaster because then, until the phone is turned, all the controls ( finger position, object position,..) are wrong. Share this post Link to post
Rollo62 536 Posted October 14, 2019 (edited) Looking for a solution too, since I used same code as yours. Seems that SetStatusBar was deprecated, and now in iOS 13 its probably gone.https://stackoverflow.com/questions/7030682/ios-iphone-ipad-sdk-alternative-for-uiapplication-sharedapplication-setst https://developer.apple.com/documentation/uikit/uiapplication/1623026-statusbarorientation Edited October 14, 2019 by Rollo62 Share this post Link to post
gioma 19 Posted October 15, 2019 Yes, I know that the SetStatusBar function is obsolete and now there is no other function to do it. I found a solution, to open the module that I would like to show only in Landscape, I show a message to the user to inform him that he must rotate the phone to open it. Then, when the user rotates the phone, the "onResize" event is activated. In this event the orientation is set only to Landscape and then the form is opened. Share this post Link to post
Rollo62 536 Posted October 15, 2019 Ok, that is a workaround. But I hope that there is a better way ... Apple strikes back on iOS13 again ... I'm just still fixing other similar issues. Share this post Link to post
Dave Nottage 557 Posted August 3, 2020 @Rollo62Did you manage to come up with a solution for this? I'm looking for one, and it is proving to be elusive 🙂 Share this post Link to post
Rollo62 536 Posted August 3, 2020 I still have a "manual" solution implemented, which gives advice to the user howto set-up the right orientation. Not perfect, but no time to search for a better one right now. Since its happening only in a remore place in one app, its acceptable for me. Share this post Link to post
Dave Nottage 557 Posted August 3, 2020 24 minutes ago, Rollo62 said: I still have a "manual" solution implemented, which gives advice to the user howto set-up the right orientation. In my case, it's not about advising the user how to set up anything: Application.FormFactor.Orientations takes care of which orientations the app will support. The issue is with re-orienting the app once Application.FormFactor.Orientations has been changed at runtime. Currently, the user has to rotate the device themselves. Share this post Link to post
Rollo62 536 Posted August 3, 2020 Thats what I meant too: - if device is currently in landscape, - the user switches a button to show a new page which requires Portrait mode - give the user an advice that turning the device is necessary before, or - possible too that the new mode appears automatically, when the user has turned the device into portrait 1 Share this post Link to post
Dave Nottage 557 Posted May 8 Thanks to a message from @Stewag, I've been prompted to revisit this issue. The following code works on iOS 17. I expect it'll work on iOS 16 - not sure about earlier: unit Unit1; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.fmx} uses Macapi.ObjectiveC, Macapi.Helpers, iOSapi.Foundation, iOSapi.UIKit, iOSapi.Helpers; type UIViewControllerEx = interface(UIViewController) ['{3E6C5FB2-20F2-4B42-BFD8-33968A80E809}'] procedure setNeedsUpdateOfSupportedInterfaceOrientations; cdecl; end; TUIViewControllerEx = class(TOCGenericImport<UIViewControllerClass, UIViewControllerEx>) end; procedure TForm1.Button1Click(Sender: TObject); var LID: Pointer; begin Application.FormFactor.Orientations := [TScreenOrientation.Portrait, TScreenOrientation.InvertedPortrait]; if TOSVersion.Check(16) then begin LID := NSObjectToID(TiOSHelper.SharedApplication.keyWindow.rootViewController); TUIViewControllerEx.Wrap(LID).setNeedsUpdateOfSupportedInterfaceOrientations; end else TUIViewController.OCClass.attemptRotationToDeviceOrientation; end; If you run the app, then turn the device so that it is in landscape orientation, then click the button, it'll reorient the app into portrait. Share this post Link to post
Stewag 0 Posted May 13 (edited) procedure TfMain.IOSTurn(Portrait: boolean); // Source: https://en.delphipraxis.net/topic/1796-firemonkey-change-ios-screen-rotation-at-runtime/ var LID: Pointer; begin if Portrait then begin Application.FormFactor.Orientations := [TScreenOrientation.Portrait, TScreenOrientation.InvertedPortrait]; if not TOSVersion.Check(16) then // iOS lower than 16 begin showmessage('Please turn phone back to portrait'); TurnIOStoPortrait := False; // turn off message to prevent multiple display end; end else begin Application.FormFactor.Orientations := [TScreenOrientation.Landscape, TScreenOrientation.InvertedLandscape]; end; if TOSVersion.Check(16) then // iOS Version 16 and up begin LID := NSObjectToID(TiOSHelper.sharedApplication.keyWindow.rootViewController); TUIViewControllerEx.Wrap(LID).setNeedsUpdateOfSupportedInterfaceOrientations; end else // iOS 13: no automatic rotation. Not tested for iOS<13 begin TUIViewController.OCClass.attemptRotationToDeviceOrientation; if TabControl1.ActiveTab.Name = 'XXX' then // limit message to specific tab showmessage('Please turn phone to landscape'); end end; Dave's code works magnificently - thank you Dave! Here is an alternative procedure to Dave's Button1Click() that works both ways and includes messages to rotate the phone manually. This is necessary for iOS lower than 16, where the content but not the display is rotated by the code. In IOS 16 and up, rotation is done smoothly automatically. I could only test iOS 13 though, maybe someone can extend the code to iOS < 13? Steffen Edited May 13 by Stewag Share this post Link to post
Rollo62 536 Posted May 13 (edited) I can conform Daves code too, works well here also 👍. 3 hours ago, Stewag said: if TabControl1.ActiveTab.Name = 'XXX' then // limit message to specific tab showmessage('Please turn phone to landscape'); What I've implemented in the former manual approach, was a system that shows a message and listens to the user turning the screen into the right position, handled by anonymous method. My goal was to distract the user as little as possible from his normal workflow, not enforcing him to press and buttons. class procedure TCore_Orientation.SetCurrent( const AOrientNew : TScreenOrientation; const AOrientPossible : TScreenOrientations; const ANotifyWhenReady : TProc ); begin // Use an anonymous method, to notify the change to the caller FNotifyWhenReady := ANotifyWhenReady; // Do whatever is necessary, either direct or after users message. // Register my ApplicationEvent handler, that listens to the change has occured, if that is necessary end; ... // How to use it in the caller TCore_Orientation.SetCurrent( TScreenOrientation.Portrait, // Desired orientation [ TScreenOrientation.Portrait, // Possible orientations allowed TScreenOrientation.InvertedPortrait ], procedure // Wait until User turned it as desired, or after it was set by hardware. Never reach this when cancelled. begin // Do whatever you wanted to do, after desired orientation is finally set up (triggered by ApplicationEvent or direct) end ); ... end; Edited May 13 by Rollo62 Share this post Link to post