Delphi/Firemonkey Изменение поворота экрана 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;

Взято отсюда: Как предотвратить экран ротация с разработкой Android в Delphi xe5 Firemonkey

ScreenService.SetScreenOrientation выполняется и не вызывает исключения, но ориентация не изменяется, я также установил Включить пользовательскую ориентацию в Project>Options>Application>Orientation, но это также не имело никакого эффекта. .

Что для меня странно, так это то, что если это не поддерживалось, то не должно ли это

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

Вернуть ложь? и даже не войти в начало

Я добавил тестовую кнопку, чтобы проверить ориентацию экрана после того, как установил альбомную ориентацию только с помощью

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;

И если он был в портретном режиме после установки его в альбомный режим, он все еще говорит «Портрет».

Обновление 1: я также пытался изменить

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

to

OrientSet := [TScreenOrientation.Landscape]

но поведение осталось прежним


person Peter-John Jansen    schedule 28.10.2015    source источник


Ответы (1)


Хорошо, эта ротация заставила меня углубиться в iOS API, чтобы выяснить, как iOS управляет ориентацией.

Поскольку вы не можете имитировать вращение или заставить устройство иметь определенную ориентацию устройства в iOS, у вас есть довольно много ориентаций, которые следует учитывать.

  • Ориентация устройства
  • Ориентация строки состояния
  • Ориентация контроллера UIView

Ориентацию устройства нельзя принудительно изменить или изменить, это всегда будет показывать ориентацию вашего устройства в данный момент.

Однако ориентация строки состояния всегда имела процедуру setStatusBarOrientation, которую вы могли вызвать и указать желаемую ориентацию, но она была помечена как устаревшая и, следовательно, не работала, но я не получил внешнего исключения, когда я вызвал функцию, которая что он все еще был там, он просто не работал.

потом я прочитал это:

Метод setStatusBarOrientation:animated: не устарел. Теперь он работает только в том случае, если метод supportInterfaceOrientations самого верхнего полноэкранного контроллера возвращает 0.

Я тогда решил попробовать это

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

И он работает с изменением ориентации строки состояния, но, как упоминалось выше, этот протокол устарел, поэтому на каком-то этапе он может/отпадет, и это больше не будет работать.

но это только изменило вращение строки состояния и всех предупреждений и т. д., но фактическое содержимое в корневом контроллере все еще находится в портрете в моем случае, когда я хочу изменить ландшафт.

Затем я подумал, что если бы я в Delphi перешел в Application-> Orientation-> Enable custom rotate и сказал, что альбом только тогда приложение будет отображаться только в альбомной ориентации, и это прекрасно, потому что когда форма создается, а затем rootViewcontroller становится поддерживаемым интерфейсом ориентация, которая возвращается, является только альбомной, а Viewcontroller переходит в альбомную.

Поскольку, когда ваше устройство меняет ориентацию устройства, ориентация оценивается по сравнению с поддерживаемыми интерфейсами Viewcontroller, если ориентация не поддерживается, она просто не поворачивается.

Но когда назначается новый rootviewcontroller, графический интерфейс должен быть обновлен для отображения в тех ориентациях, которые поддерживаются Viewcontrollers, с учетом этого, вот мое исправление/хак, чтобы изменить ориентацию вашего приложения на нужную вам ориентацию.

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;

Все, что вам нужно сделать сейчас, это позвонить ChangeiOSorientation(toOrientation,possibleOrientations)

Если вы хотите, чтобы он шел в портретном режиме, но в качестве опции был альбомный

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

Это работает над

  • Делфи 10 Сиэтл
  • iPhone 5 под управлением iOS 9.0
  • PA-сервер 17.0
  • Xcode 7.1
  • SDK для iPhoneOS 9.1
person Peter-John Jansen    schedule 10.11.2015