Есть ли документальный способ настройки ориентации iPhone?

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

В UIDevice есть недокументированный набор свойств, который делает трюк, но, очевидно, генерирует предупреждение компилятора и может исчезнуть с будущей версией SDK.

[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];

Существуют ли какие-либо документированные способы принудительной ориентации?

Обновление: Я думал, что приведу пример, поскольку я не ищу shouldAutorotateToInterfaceOrientation, поскольку я уже реализовал это.

Я хочу, чтобы мое приложение поддерживало пейзаж и портрет в представлении 1, но только портрет в представлении 2. Я уже реализовал shouldAutorotateToInterfaceOrientation для всех представлений, но если пользователь находится в ландшафтном режиме в представлении 1, а затем переключается на вид 2, я хочу для поворота телефона назад в положение "Портрет".

Ответ 1

Это больше не проблема в более позднем iPhone 3.1.2 SDK. Похоже, что он соблюдает запрошенную ориентацию вида, отбрасываемого назад в стек. Вероятно, это означает, что вам нужно будет обнаруживать старые версии ОС для ОС iPhone и применять приложение setOrientation только до последней версии.

Неясно, будет ли Apple статический анализ понять, что вы работаете с более старыми ограничениями SDK. Я лично сказал Apple, чтобы удалить вызов метода на моем следующем обновлении, поэтому я еще не уверен, что если взломать старые устройства, то процесс прохождения будет проходить через.

Ответ 2

Это уже давно после факта, но на всякий случай приходит кто-то, кто не использует навигационный контроллер и/или не хочет использовать недокументированные методы:

UIViewController *c = [[UIViewController alloc]init];
[self presentModalViewController:c animated:NO];
[self dismissModalViewControllerAnimated:NO];
[c release];

Достаточно представить и отклонить контроллер просмотра ванили.

Очевидно, вам все равно нужно подтвердить или отклонить ориентацию в вашем переопределении toAutorotateToInterfaceOrientation. Но это приведет к тому, что wasAutorotate... будет снова вызван системой.

Ответ 3

Из того, что я могу сказать, метод setOrientation: не работает (или, возможно, больше не работает). Вот что я делаю для этого:

сначала укажите это в верхней части вашего файла, прямо под вашим #imports:

#define degreesToRadian(x) (M_PI * (x) / 180.0)

то в методе viewWillAppear:

[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];     
if (self.interfaceOrientation == UIInterfaceOrientationPortrait) {  
    self.view.transform = CGAffineTransformIdentity;
    self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
    self.view.bounds = CGRectMake(0.0, 0.0, 480, 320);
}

если вы хотите, чтобы это было анимировано, вы можете обернуть все это в блок анимации, например:

[UIView beginAnimations:@"View Flip" context:nil];
[UIView setAnimationDuration:1.25];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];

[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];     
if (self.interfaceOrientation == UIInterfaceOrientationPortrait) {  
    self.view.transform = CGAffineTransformIdentity;
    self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
    self.view.bounds = CGRectMake(0.0, 0.0, 480, 320);
}
[UIView commitAnimations];

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

Ответ 4

Если вы хотите заставить его повернуть с портрета на пейзаж, вот код. Просто отметьте, что вам нужно настроить центр своего вида. Я заметил, что мое место не поместило точку зрения в нужное место. В противном случае он работал отлично. Спасибо за подсказку.

if(UIInterfaceOrientationIsLandscape(self.interfaceOrientation)){

        [UIView beginAnimations:@"View Flip" context:nil];
        [UIView setAnimationDuration:0.5f];
        [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];

        self.view.transform = CGAffineTransformIdentity;
        self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
        self.view.bounds = CGRectMake(0.0f, 0.0f, 480.0f, 320.0f);
        self.view.center = CGPointMake(160.0f, 240.0f);

        [UIView commitAnimations];
}

Ответ 5

У меня была проблема, когда у меня был UIViewController на экране, в UINavigationController, в альбомной ориентации. Однако, когда следующий контроллер потока вдвинут в поток, мне нужно, чтобы устройство вернулось в портретную ориентацию.

То, что я заметил, заключалось в том, что метод shouldAutorotateToInterfaceOrientation: не вызывается, когда новый контроллер представления помещается в стек, но он вызывается, когда диспетчер представлений выгружается из стека.

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

- (void)selectHostingAtIndex:(int)hostingIndex {

    self.transitioning = YES;

    UIViewController *garbageController = [[[UIViewController alloc] init] autorelease];
    [self.navigationController pushViewController:garbageController animated:NO];
    [self.navigationController popViewControllerAnimated:NO];

    BBHostingController *hostingController = [[BBHostingController alloc] init];
    hostingController.hosting = [self.hostings objectAtIndex:hostingIndex];
    [self.navigationController pushViewController:hostingController animated:YES];
    [hostingController release];

    self.transitioning = NO;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    if (self.transitioning)
        return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
    else
        return YES;
}

В принципе, создав пустой контроллер представлений, нажав его в стек и сразу же вытащив его, можно вернуть интерфейс в портретную позицию. Как только контроллер выскочил, я просто нажимаю на контроллер, который я намеревался нажать в первую очередь. Визуально это выглядит великолепно - пустой, произвольный контроллер просмотра никогда не видит пользователь.

Ответ 6

Я копаю и копаю, ища хорошее решение для этого. Нашел этот пост в блоге, который делает трюк: удалите свой внешний вид из ключа UIWindow и добавьте его снова, система снова запросит методы shouldAutorotateToInterfaceOrientation: из ваших контроллеров view, соблюдая правильную ориентацию, которая будет применяться. Смотрите: iphone заставляет uiview переориентировать

Ответ 7

Существует простой способ программно заставлять iPhone иметь необходимую ориентацию - используя два уже предоставленных ответа kdbdallas, Josh:

//will rotate status bar
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];


//will re-rotate view according to statusbar
UIViewController *c = [[UIViewController alloc]init];
[self presentModalViewController:c animated:NO];
[self dismissModalViewControllerAnimated:NO];
[c release];

работает как шарм:)

EDIT:

для iOS 6 Мне нужно добавить эту функцию: (работает над модальным контроллером просмотра)

- (NSUInteger)supportedInterfaceOrientations
{
    return (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight);
}

Ответ 8

Ответ Джоша отлично работает для меня.

Тем не менее, я предпочитаю публиковать уведомление об изменении ориентации, пожалуйста, обновите UI. Когда это уведомление получено контроллером представления, он вызывает shouldAutorotateToInterfaceOrientation:, что позволяет вам установить любую ориентацию, возвращая YES для нужной ориентации.

[[NSNotificationCenter defaultCenter] postNotificationName:UIDeviceOrientationDidChangeNotification object:nil];

Единственная проблема заключается в том, что это приводит к переориентации без анимации. Для достижения плавного перехода вам понадобится обернуть эту строку между beginAnimations: и commitAnimations.

Надеюсь, что это поможет.

Ответ 9

FWIW, здесь моя реализация ориентации ручной настройки (для входа в контроллер корневого приложения вашего приложения, natch):

-(void)rotateInterfaceToOrientation:(UIDeviceOrientation)orientation{

    CGRect bounds = [[ UIScreen mainScreen ] bounds ];
    CGAffineTransform t;
    CGFloat r = 0;
    switch ( orientation ) {
        case UIDeviceOrientationLandscapeRight:
            r = -(M_PI / 2);
            break;
        case UIDeviceOrientationLandscapeLeft:
            r  = M_PI / 2;
            break;
    }
    if( r != 0 ){
        CGSize sz = bounds.size;
        bounds.size.width = sz.height;
        bounds.size.height = sz.width;
    }
    t = CGAffineTransformMakeRotation( r );

    UIApplication *application = [ UIApplication sharedApplication ];

    [ UIView beginAnimations:@"InterfaceOrientation" context: nil ];
    [ UIView setAnimationDuration: [ application statusBarOrientationAnimationDuration ] ];
    self.view.transform = t;
    self.view.bounds = bounds;
    [ UIView commitAnimations ];

    [ application setStatusBarOrientation: orientation animated: YES ];     
}

в сочетании со следующим методом UINavigationControllerDelegate (при условии, что вы используете UINavigationController):

-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
    // rotate interface, if we need to
    UIDeviceOrientation orientation = [[ UIDevice currentDevice ] orientation ];
    BOOL bViewControllerDoesSupportCurrentOrientation = [ viewController shouldAutorotateToInterfaceOrientation: orientation ];
    if( !bViewControllerDoesSupportCurrentOrientation ){
        [ self rotateInterfaceToOrientation: UIDeviceOrientationPortrait ];
    }
}

Это касается поворота корневого представления в зависимости от того, поддерживает ли входящий UIViewController текущую ориентацию устройства. Наконец, вы захотите подключить rotateInterfaceToOrientation к фактическим изменениям ориентации устройства, чтобы имитировать стандартную функциональность iOS. Добавьте этот обработчик событий в тот же контроллер корневого представления:

-(void)onUIDeviceOrientationDidChangeNotification:(NSNotification*)notification{
    UIViewController *tvc = self.rootNavigationController.topViewController;
    UIDeviceOrientation orientation = [[ UIDevice currentDevice ] orientation ];
    // only switch if we need to (seem to get multiple notifications on device)
    if( orientation != [[ UIApplication sharedApplication ] statusBarOrientation ] ){
        if( [ tvc shouldAutorotateToInterfaceOrientation: orientation ] ){
            [ self rotateInterfaceToOrientation: orientation ];
        }
    }
}

Наконец, зарегистрируйтесь для уведомлений UIDeviceOrientationDidChangeNotification в init или loadview так:

[[ NSNotificationCenter defaultCenter ] addObserver: self
                                           selector: @selector(onUIDeviceOrientationDidChangeNotification:)
                                               name: UIDeviceOrientationDidChangeNotification
                                             object: nil ];
[[ UIDevice currentDevice ] beginGeneratingDeviceOrientationNotifications ];

Ответ 10

Это работает для меня (спасибо Henry Cooke):

Цель для меня состояла в том, чтобы иметь дело только с изменениями ландшафтной ориентации.

метод init:

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(orientationChanged:)
                                             name:UIDeviceOrientationDidChangeNotification
                                           object:nil];

- (void)orientationChanged:(NSNotification *)notification {    
    //[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
    UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
    CGRect bounds = [[ UIScreen mainScreen ] bounds ];
    CGAffineTransform t;
    CGFloat r = 0;
    switch ( orientation ) {
        case UIDeviceOrientationLandscapeRight:
            r = 0;
            NSLog(@"Right");
            break;
        case UIDeviceOrientationLandscapeLeft:
            r  = M_PI;
            NSLog(@"Left");
            break;
        default:return;
    }

    t = CGAffineTransformMakeRotation( r );

    UIApplication *application = [ UIApplication sharedApplication ];
    [ UIView beginAnimations:@"InterfaceOrientation" context: nil ];
    [ UIView setAnimationDuration: [ application statusBarOrientationAnimationDuration ] ];
    self.view.transform = t;
    self.view.bounds = bounds;
    [ UIView commitAnimations ];

    [ application setStatusBarOrientation: orientation animated: YES ];
}

Ответ 11

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

Я понимаю, что вышеупомянутый исходный пост в этой теме очень старый, но у меня была с ним аналогичная проблема, т.е. все экраны в моем приложении - только портреты, за исключением одного экрана, который пользователь может поворачивать между пейзажем и портретом.

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

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

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)pInterfaceOrientation {
    BOOL lHideNavBar = self.interfaceOrientation == UIInterfaceOrientationPortrait ? NO : YES;
    [self.navigationController setNavigationBarHidden:lHideNavBar animated:YES];
}

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

Надеюсь, что это поможет.

Ответ 12

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

В ViewController, который должен остаться Landscape (Left или Right), я слушаю изменения ориентации:

    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(didRotate:)
                                             name:UIDeviceOrientationDidChangeNotification object:nil];

Затем в didRotate:

- (void) didRotate:(NSNotification *)notification
{   if (orientationa == UIDeviceOrientationPortrait) 
    {
        if (hasRotated == NO) 
        {
            NSLog(@"Rotating to portait");
            hasRotated = YES;
            [UIView beginAnimations: @"" context:nil];
            [UIView setAnimationDuration: 0];
            self.view.transform = CGAffineTransformIdentity;
            self.view.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(-90));
            self.view.bounds = CGRectMake(0.0f, 0.0f, 480.0f, 320.0f);
            self.view.frame = CGRectMake(0.0f, 0.0f, 480.0f, 320.0f);
            [UIView commitAnimations];

    }
}
else if (UIDeviceOrientationIsLandscape( orientationa))
{
    if (hasRotated) 
    {
        NSLog(@"Rotating to lands");
        hasRotated = NO;
        [UIView beginAnimations: @"" context:nil];
        [UIView setAnimationDuration: 0];
        self.view.transform = CGAffineTransformIdentity;
        self.view.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(0));
        self.view.bounds = CGRectMake(0.0f, 0.0f, 320.0f, 480.0f);
        self.view.frame = CGRectMake(0.0f, 0.0f, 320.0f, 480.0f);
        [UIView commitAnimations];

    }
}

Имейте в виду все суперспекты/подзаголовки, которые используют авторезистентность, так как view.bounds/frame явно reset...

Единственное предостережение в этом методе сохранения пейзажа "Ландшафт" - это неотъемлемая анимация переключения между ориентациями, которые должны произойти, когда было бы лучше, чтобы она не изменилась.

Ответ 13

Решение iOS 6:

[[[self window] rootViewController] presentViewController:[[UIViewController alloc] init] animated:NO completion:^{
    [[[self window] rootViewController] dismissViewControllerAnimated:NO completion:nil];
}];

Точный код зависит от каждого приложения, а также от места его размещения (я использовал его в своем AppDelegate). Замените [[self window] rootViewController] тем, что вы используете. Я использовал UITabBarController.

Ответ 14

Я нашел решение и написал что-то на французском (но код на английском). здесь

Путь заключается в том, чтобы добавить контроллер в окно (контроллер должен обладать хорошей реализацией функции shouldRotate....).

Ответ 15

Если вы используете UIViewControllers, есть этот метод:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

Верните NO для контроллеров представления, содержащих просмотры, которые вы не хотите вращать.

Дополнительная информация здесь

Ответ 16

Я не думаю, что это можно сделать во время выполнения, хотя вы, конечно, можете просто применить 90-градусное преобразование к своему пользовательскому интерфейсу.

Ответ 17

Это то, что я использую. (Вы получаете некоторые компиляции предупреждений, но он работает как в Simulator, так и в iPhone)

[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];