简体   繁体   English

Delphi / Firemonkey在运行时更改iOS屏幕旋转

[英]Delphi/Firemonkey Change iOS screen rotation at runtime

basically all I want to achieve is when a user is in a certain part of the App to change the screen rotation as needed, I have this working for Andriod and I can not see why it shouldn't work for iOS 基本上我想要实现的是当用户在应用程序的某个部分根据需要更改屏幕旋转时,我有这个为Andriod工作,我不明白为什么它不应该适用于iOS

procedure TForm1.Button1Click(Sender: TObject);
var
  ScreenService: IFMXScreenService;
  OrientSet: TScreenOrientations;
begin
    if TPlatformServices.Current.SupportsPlatformService(IFMXScreenService, IInterface(ScreenService)) 
    then
    begin
        OrientSet := [TScreenOrientation.soLandscape];//<- Break point set here and line is executed
        ScreenService.SetScreenOrientation(OrientSet);
    end;
end;

Taken from here : How to prevent screen rotation with android development in delphi xe5 Firemonkey 从这里采取: 如何在delphi xe5 Firemonkey中使用android开发防止屏幕旋转

The ScreenService.SetScreenOrientation is executed and does not raise a exception but the orientation is not changed, I have also set Enable custom orientation in Project>Options>Application>Orientation but this also didn't have any effect. ScreenService.SetScreenOrientation已执行且不会引发异常,但方向未更改,我还在Project> Options> Application> Orientation中设置了Enable custom orientation ,但这也没有任何效果。

What is strange to me is that if it was not supported then shouldn't this 对我来说奇怪的是,如果不支持,那么不应该这样

if TPlatformServices.Current.SupportsPlatformService(IFMXScreenService, IInterface(ScreenService)) 

Return false? 回报错误? and not even enter the begin 甚至没有进入开始

I added a test button to check the screen orientation after I set it to landscape only with 我添加了一个测试按钮来检查屏幕方向后,我将其设置为横向

if TPlatformServices.Current.SupportsPlatformService(IFMXScreenService, IInterface(ScreenService)) 
then
begin
    case ScreenService.GetScreenOrientation of
        TScreenOrientation.Portrait: ShowMessage('Portrait');
        TScreenOrientation.Landscape: ShowMessage('landscape');
        TScreenOrientation.InvertedPortrait: ShowMessage('Inverted-Portrait');
        TScreenOrientation.InvertedLandscape: ShowMessage('Inverted-Landscape');
        else ShowMessage('not set');
    end;
end;

And if it was in Portrait after setting it to Landscape it still says Portrait 如果在将它设置为横向之后它在纵向中,它仍然会说肖像

Update 1 : I have also tried changing 更新1 :我也试过改变

OrientSet := [TScreenOrientation.soLandscape] // <- Deprecated

to

OrientSet := [TScreenOrientation.Landscape]

but the behaviour is still the same 但行为仍然是一样的

Ok this rotation had me digging deep into the iOS API to figure out how iOS manages orientation. 好的,这次轮换让我深入研究iOS API,以了解iOS如何管理方向。

Because you can not fake a rotation or force a device certain device orientation in iOS in iOS you have quite a few orientations to consider 因为您无法在iOS中的iOS中伪造旋转或强制设备某些设备方向 ,所以您需要考虑很多方向

  • Device Orientation 设备方向
  • Statusbar orientation 状态栏方向
  • UIViewcontroller orientation UIViewcontroller方向

The device orientation can not be forced or altered this will always show the orientation your device is in now. 无法强制或更改设备方向,这将始终显示设备现在的方向。

The statusbar orientation however has always had the setStatusBarOrientation procedure you could call and spesify the orientation you wanted, but this was marked as deprecated, and thus was not working, but I didn't get a external exception when I called the function, which ment that it was still there, it just wasn't working. 然而,状态栏方向总是有你可以调用的setStatusBarOrientation过程并且指定你想要的方向,但是这被标记为已弃用,因此无效,但是当我调用该函数时,我没有得到外部异常。它仍然存在,它只是没有工作。

then I read this : 然后我读到了这个:

The setStatusBarOrientation:animated: method is not deprecated outright. setStatusBarOrientation:animated:方法不会被完全弃用。 It now works only if the supportedInterfaceOrientations method of the top-most full-screen view controller returns 0 现在,只有当最顶层的全屏视图控制器的supportedInterfaceOrientations方法返回0时,它才有效

I then decided to try this 然后我决定尝试这个

Application.FormFactor.Orientations := []; //the supportedInterfaceOrientations returns 0
App := TUIApplication.Wrap(TUIApplication.OCClass.sharedApplication);
win := TUIWindow.Wrap(App.windows.objectAtIndex(0));
App.setStatusBarOrientation(UIInterfaceOrientationLandscapeLeft);

And it works the statusbar orientation changes, but like mentioned above, this protocol is deprecated so at some stage it can/will fall away and this will no longer work. 并且它适用于状态栏方向更改,但如上所述,此协议已弃用,因此在某个阶段它可能/将会消失,这将不再起作用。

but this only changed the rotation of the statusbar and all alertviews etc, but the actual content within the rootviewcontroller is still in the Portrait in my case of wanting to change to landscape. 但是这只改变了状态栏和所有警报视图等的旋转,但是在我想要更改为横向的情况下,rootviewcontroller中的实际内容仍然在肖像中。

I then tought if I would in Delphi would go to Application->Orientation-> Enable custom rotation and say landscape only then the App will only display in landscape, and it does perfectly because when the form is created and then rootViewcontroller is made the supportedInterface orientations that is returned is only landscape and the Viewcontroller goes to Landscape. 然后,如果我想在Delphi中转到Application-> Orientation->启用自定义旋转并说景观,那么App只会以横向显示,并且它完美地完成,因为在创建表单然后rootViewcontroller成为supportedInterface返回的方向只是横向,Viewcontroller转到Landscape。

Because when your device changes device orientation the orientation is evaluated against the Viewcontroller's supportedinterfaceorientations, if the orientation is not supported it is simply not rotated. 因为当您的设备更改设备方向时,将根据Viewcontroller支持的接口方向评估方向,如果不支持方向,则不会旋转方向。

But when a new rootviewcontroller is assigned the GUI has to be updated to display in that Viewcontrollers supported orientations, with that in mind, here is my fix/hack to change the orientation of your App to a orientation you want. 但是当分配新的rootviewcontroller时,必须更新GUI以在Viewcontrollers支持的方向中显示,考虑到这一点,这是我的修复/黑客将应用程序的方向更改为您想要的方向。

TL;DR TL; DR

Uses: iOSapi.UIKit; 

procedure ChangeiOSorientation(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;

All you have to do now is Call ChangeiOSorientation(toOrientation,possibleOrientations) 你现在所要​​做的就是调用ChangeiOSorientation(toOrientation,possibleOrientations)

If you want it to go to Portrait but have landscape as a option 如果您想要它去Portrait,但可以选择横向

 ChangeiOSorientation(UIInterfaceOrientationPortrait,[TScreenOrientation.Portrait,TScreenOrientation.Landscape,TScreenOrientation.InvertedLandscape]);    

This is working on 这是在努力

  • Delphi 10 Seattle 德尔福10西雅图
  • iPhone 5 running iOS 9.0 iPhone 5运行iOS 9.0
  • PA Server 17.0 PA服务器17.0
  • Xcode 7.1 Xcode 7.1
  • iPhoneOS 9.1 SDK iPhoneOS 9.1 SDK

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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