Есть ли документированный способ установки ориентации iPhone? - PullRequest
94 голосов
/ 08 октября 2008

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

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

[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];

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

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

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

Ответы [ 17 ]

101 голосов
/ 06 февраля 2011

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

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

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

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

16 голосов
/ 27 апреля 2009

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

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];
}
16 голосов
/ 21 января 2009

Из того, что я могу сказать, метод 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];

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

7 голосов
/ 20 августа 2010

У меня была проблема, когда у меня было 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;
}

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

7 голосов
/ 09 мая 2012

Существует простой способ программно перевести 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 Мне нужно добавить эту функцию: (работает на модальном viewcontroller)

- (NSUInteger)supportedInterfaceOrientations
{
    return (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight);
}
7 голосов
/ 27 октября 2010

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

6 голосов
/ 05 декабря 2009

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

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

5 голосов
/ 13 июня 2011

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

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

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

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

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

3 голосов
/ 07 декабря 2010

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

-(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 ];
2 голосов
/ 18 апреля 2011

Это работает для меня (спасибо Генри Кук):

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

метод инициализации:

[[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 ];
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...