Existe uma maneira documentada de definir a orientação do iPhone?

Eu tenho um aplicativo onde eu gostaria de apoiar a rotação do dispositivo em certas vistas, mas outras não fazem sentido no modo Paisagem, então, ao trocar as vistas, gostaria de forçar a rotação a ser definida para retrato.

Há um setter de propriedade não documentado no UIDevice que faz o truque, mas obviamente gera um aviso do compilador e pode desaparecer com uma revisão futura do SDK.

[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait]; 

Existem maneiras documentadas de forçar a orientação?

Atualização: Eu pensei em fornecer um exemplo, já que não estou procurando shouldAutorotateToInterfaceOrientation, pois já implementei isso.

Eu quero que meu aplicativo suporte paisagem e retrato na Visualização 1, mas apenas retrato na Visualização 2. Eu já implementei shouldAutorotateToInterfaceOrientation para todas as visualizações, mas se o usuário estiver no modo paisagem na Visualização 1 e alternar para a Visualização 2, eu quero forçar a telefone para girar de volta para Retrato.

Isso não é mais um problema no iPhone 3.1.2 SDK. Agora, parece honrar a orientação solicitada da visão sendo empurrada de volta para a pilha. Isso provavelmente significa que você precisaria detectar versões mais antigas do iPhone OS e aplicar apenas o setOrientation quando estiver antes da última versão.

Não está claro se a análise estática da Apple entenderá que você está trabalhando com as limitações mais antigas do SDK. Pessoalmente, a Apple me disse para remover a chamada do método na minha próxima atualização, então ainda não tenho certeza se ter um hack para dispositivos mais antigos passará pelo processo de aprovação.

Isso é muito depois do fato, mas apenas no caso de alguém aparecer que não esteja usando um controlador de navegação e / ou não queira usar methods não documentados:

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

É suficiente para apresentar e descartar um controlador de exibição baunilha.

Obviamente, você ainda precisará confirmar ou negar a orientação em sua substituição de shouldAutorotateToInterfaceOrientation. Mas isso fará com que shouldAutorotate … seja chamado novamente pelo sistema.

Se você quiser forçá-lo a girar de retrato para paisagem, aqui está o código. Apenas note que você precisa ajustar o centro da sua visão. Percebi que o meu não colocava a vista no lugar certo. Caso contrário, funcionou perfeitamente. Obrigado pela dica.

 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]; } 

Pelo que eu posso dizer, o setOrientation: não funciona (ou talvez não funcione mais). Veja o que estou fazendo para fazer isso:

Primeiro, coloque essa definição no topo do seu arquivo, logo abaixo do #imports:

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

então, no método 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); } 

Se você quer que seja animado, então você pode envolver tudo em um bloco de animação, assim:

 [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]; 

Em seguida, no seu controlador de modo retrato, você pode fazer o inverso – verifique se ele está no modo paisagem e, em caso afirmativo, gire-o de volta para Retrato.

Eu estava tendo um problema onde eu tinha um UIViewController na canvas, em um UINavigationController , na orientação paisagem. Quando o próximo controlador de visualização é empurrado no stream, no entanto, precisei que o dispositivo retornasse à orientação de retrato.

O que eu notei foi que o método shouldAutorotateToInterfaceOrientation: não é chamado quando um novo controlador de visão é colocado na pilha, mas é chamado quando um controlador de visão é retirado da pilha .

Aproveitando isso, estou usando esse snippet de código em um dos meus apps:

 - (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; } 

Basicamente, criando um controlador de visão vazio, empurrando-o para a pilha e imediatamente removendo-o, é possível fazer com que a interface volte à posição de retrato. Uma vez que o controle foi triggersdo, eu apenas empurro o controle que eu pretendia empurrar em primeiro lugar. Visualmente, parece ótimo – o controlador de exibição arbitrário e vazio nunca é visto pelo usuário.

Existe uma maneira simples de forçar programaticamente o iPhone para a orientação necessária – usando duas das respostas já fornecidas pelo 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]; 

Funciona como um encanto 🙂

EDITAR:

para iOS 6 eu preciso adicionar esta function: (funciona no viewcontroller modal)

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

Eu tenho cavado e cavado procurando por uma boa solução para isso. Encontrei esta postagem do blog que faz o truque: remova sua visualização mais externa da chave UIWindow e a inclua novamente, o sistema consultará novamente os methods shouldAutorotateToInterfaceOrientation: de seus viewcontrollers, aplicando a orientação correta a ser aplicada. Veja: iphone forçando uiview para reorientar

A resposta de Josh funciona bem para mim.

No entanto, eu prefiro postar uma notificação de “orientação mudou, por favor, atualize a interface do usuário” . Quando essa notificação é recebida por um controlador de exibição, ela chama shouldAutorotateToInterfaceOrientation: permitindo que você defina qualquer orientação retornando YES para a orientação desejada.

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

O único problema é que isso força uma reorientação sem uma animação. Você precisaria quebrar essa linha entre beginAnimations: e commitAnimations para alcançar uma transição suave.

Espero que ajude.

FWIW, aqui está minha implementação de configurar manualmente a orientação (para entrar no controlador de visão raiz do seu aplicativo, 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 ]; } 

juntamente com o seguinte método UINavigationControllerDelegate (supondo que você esteja usando um 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 ]; } } 

Isso cuida de rotacionar a visualização da raiz de acordo com o fato de um UIViewController input suportar a orientação atual do dispositivo. Finalmente, você vai querer ligar o rotateInterfaceToOrientation às mudanças reais de orientação do dispositivo para imitar a funcionalidade padrão do iOS. Adicione este manipulador de events ao mesmo controlador de visualização raiz:

 -(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 ]; } } } 

Por fim, registre UIDeviceOrientationDidChangeNotification notifications do UIDeviceOrientationDidChangeNotification no init ou no loadview forma:

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

Isso funciona para mim (obrigado Henry Cooke):

O objective para mim era lidar apenas com mudanças de orientações de paisagem.

método 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 ]; } 

Eu tenho um aplicativo onde eu gostaria de apoiar a rotação do dispositivo em certas vistas, mas outras não fazem sentido no modo Paisagem, então, ao trocar as vistas, gostaria de forçar a rotação a ser definida para retrato.

Eu percebo que o post original acima neste tópico é muito antigo agora, mas eu tive um problema parecido com ele – ie. Todas as canvass do meu aplicativo são apenas retrato, com exceção de uma canvas, que pode ser alternada entre paisagem e retrato pelo usuário.

Isso era bastante simples, mas, como outros posts, eu queria que o aplicativo retornasse automaticamente ao retrato, independentemente da orientação atual do dispositivo, ao retornar à canvas anterior.

A solução que implementei foi a de ocultar a barra de navegação no modo paisagem, o que significa que o usuário só pode retornar às canvass anteriores enquanto está no retrato. Portanto, todas as outras canvass só podem estar em retrato.

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

Isso também tem o benefício adicional do meu aplicativo, pois há mais espaço na canvas disponível no modo paisagem. Isso é útil porque a canvas em questão é usada para exibir arquivos PDF.

Espero que isto ajude.

Eu resolvi isso com bastante facilidade no final. Eu tentei todas as sugestões acima e ainda fiquei aquém, então essa foi a minha solução:

No ViewController que precisa permanecer em Landscape (Esquerda ou Direita), eu ouço mudanças de orientação:

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

Então no 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]; } } 

Tenha em mente quaisquer Super Views / Subviews que usam o redimensionamento automático, pois as view.bounds / frame estão sendo redefinidas explicitamente …

A única ressalva a esse método para manter a visão Paisagem é a animação inerente alternando entre as orientações que precisam ocorrer, quando seria melhor que parecesse não haver nenhuma alteração.

Solução iOS 6:

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

O código exato depende por aplicativo e também onde você o coloca (eu usei em meu AppDelegate). Substitua [[self window] rootViewController] pelo que você usa. Eu estava usando um UITabBarController .

Eu encontrei uma solução e escrevi algo em francês (mas o código está em inglês). Aqui

O caminho é adicionar o controlador à visualização da janela (o controlador deve possuir uma boa implementação da function shouldRotate ….).

Se você estiver usando UIViewControllers, existe este método:

 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 

Retorna NO para os controladores de visualização que contêm as vistas que você não deseja girar.

Mais informação aqui

Eu não acho que isso é possível fazer em tempo de execução, mas você poderia, claro, apenas aplicar uma transformação de 90 graus para sua interface do usuário.

Isso é o que eu uso. (Você recebe alguns avisos de compilation, mas funciona tanto no Simulador quanto no iPhone)

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