Есть ли документальный способ настройки ориентации 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];