IOS 6: ориентация устройства на пейзаж
Я дал приложение с поддержкой 10 контроллеров. Я использую контроллер навигации для загрузки/выгрузки.
Все, кроме одного, находятся в портретном режиме. Предположим, что 7-й VC находится в ландшафте. Мне нужно, чтобы он был представлен в ландшафте, когда он загружается.
Пожалуйста, предложите способ заставить ориентацию перейти от портрета к ландшафту в IOS 6 (и будет хорошо работать и в IOS 5).
Вот как я это делал ПЕРЕД IOS 6:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
UIViewController *c = [[[UIViewController alloc]init] autorelease];
[self presentModalViewController:c animated:NO];
[self dismissModalViewControllerAnimated:NO];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
Представление и отклонение модального VC заставляло приложение просматривать его ориентацию, поэтому shouldAutorotateToInterfaceOrientation
получал вызов.
Что я пробовал в IOS 6:
- (BOOL)shouldAutorotate{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscape;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return UIInterfaceOrientationLandscapeLeft;
}
При загрузке контроллер остается в портрете. После поворота устройства ориентация меняется только нормально. Но мне нужно заставить контроллер автоматически поворачиваться на пейзаж при загрузке, поэтому пользователю придется вращать устройство, чтобы правильно видеть данные.
Другая проблема: после поворота устройства назад к портрету ориентация переходит к портрету, хотя я указал только в supportedInterfaceOrientations
UIInterfaceOrientationMaskLandscape
. Почему это происходит?
Кроме того, вызывается NONE из выше 3 методов.
Некоторые (полезные) данные:
- В моем файле plist я указал 3 ориентации - все, кроме перевернутого.
- Проект был запущен в Xcode 4.3 IOS 5. Все классы, включая xibs, были созданы до Xcode 4.5 IOS 6, теперь я использую последнюю версию.
- В файле plist строка состояния установлена на видимую.
- В файле xib (тот, который я хочу быть в ландшафте) строка состояния "Нет", ориентация установлена на альбомную.
Любая помощь приветствуется. Благодарю.
Ответы
Ответ 1
Хорошо, ребята, я отправлю свое решение.
Что у меня:
- Приложение на основе представления с несколькими контроллерами представлений. (Это была навигация, но я должен был сделать ее основанную на обзоре из-за проблем с ориентацией).
- Все контроллеры просмотра - это портрет, кроме одного - landscapeLeft.
Задачи:
- Один из моих контроллеров просмотра должен автоматически поворачиваться в альбомное, независимо от того, как пользователь держит устройство. Все остальные контроллеры должны быть портретами, и после выхода из ландшафтного контроллера приложение должно принудительно поворачиваться на портрет, неважно, снова, как пользователь держит устройство.
- Это должно работать как на IOS 6.x, так и на IOS 5.x
Go!
( Обновить Удалены макросы, предложенные @Ivan Vučica)
Во всех ваших контроллерах представления PORTRAIT переопределить методы авторотации следующим образом:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}
-(BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
Вы можете увидеть два подхода: один для IOS 5 и другой для IOS 6.
То же самое для вашего контроллера просмотра LANDSCAPE с некоторыми дополнениями и изменениями:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
[image_signature setImage:[self resizeImage:image_signature.image]];
return (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
-(BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
[image_signature setImage:[self resizeImage:image_signature.image]];
return UIInterfaceOrientationMaskLandscapeLeft;
}
ВНИМАНИЕ: чтобы заставить авторотировать в IOS 5, вы должны добавить это:
- (void)viewDidLoad{
[super viewDidLoad];
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 6.0)
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationLandscapeLeft animated:NO];
}
Аналогично, после того, как вы покинете контроллер LANDSCAPE, независимо от того, какой контроллер вы загрузите, вы должны снова включить авторотацию для IOS 5, но теперь вы будете использовать UIDeviceOrientationPortrait
, когда вы перейдете к контроллеру PORTRAIT:
- (void)viewDidLoad{
[super viewDidLoad];
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 6.0)
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationPortrait animated:NO];
}
Теперь последнее (и это немного странно) - вы должны изменить способ переключения с контроллера на другой, в зависимости от IOS:
Сделайте класс NSObject "Schalter" ( "Переключатель" на немецком языке).
В Schalter.h говорят:
#import <Foundation/Foundation.h>
@interface Schalter : NSObject
+ (void)loadController:(UIViewController*)VControllerToLoad andRelease:(UIViewController*)VControllerToRelease;
@end
В Schalter.m говорят:
#import "Schalter.h"
#import "AppDelegate.h"
@implementation Schalter
+ (void)loadController:(UIViewController*)VControllerToLoad andRelease:(UIViewController*)VControllerToRelease{
//adjust the frame of the new controller
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
CGRect windowFrame = [[UIScreen mainScreen] bounds];
CGRect firstViewFrame = CGRectMake(statusBarFrame.origin.x, statusBarFrame.size.height, windowFrame.size.width, windowFrame.size.height - statusBarFrame.size.height);
VControllerToLoad.view.frame = firstViewFrame;
//check version and go
if (IOS_OLDER_THAN_6)
[((AppDelegate*)[UIApplication sharedApplication].delegate).window addSubview:VControllerToLoad.view];
else
[((AppDelegate*)[UIApplication sharedApplication].delegate).window setRootViewController:VControllerToLoad];
//kill the previous view controller
[VControllerToRelease.view removeFromSuperview];
}
@end
СЕЙЧАС, так вы используете Schalter (предположите, что вы переходите от контроллера Warehouse к контроллеру Products):
#import "Warehouse.h"
#import "Products.h"
@implementation Warehouse
Products *instance_to_products;
- (void)goToProducts{
instance_to_products = [[Products alloc] init];
[Schalter loadController:instance_to_products andRelease:self];
}
bla-bla-bla your methods
@end
Конечно, вы должны освободить объект instance_to_products
:
- (void)dealloc{
[instance_to_products release];
[super dealloc];
}
Ну, вот и все. Не стесняйтесь ниспровергать, мне все равно. Это для тех, кто ищет решения, а не для репутации.
Ура!
Сава Мазаре.
Ответ 2
Это должно работать, похожее на версию pre-iOS 6, но с UINavigationController
:
UIViewController *portraitViewController = [[UIViewController alloc] init];
UINavigationController* nc = [[UINavigationController alloc] initWithRootViewController:portraitViewController];
[self.navigationController presentModalViewController:nc animated:NO];
[self.navigationController dismissModalViewControllerAnimated:NO];
Я вызываю это, пока не нажимаю следующий UIViewController
. Это заставит следующий нажатый UIViewController
отображаться в режиме портрета, даже если текущий UIViewController
находится в Пейзаже (также должен работать и для Portrait to Landscape). Работает на iOS 4 + 5 + 6 для меня.
Ответ 3
Я думаю, что лучшее решение - придерживаться официальной документации для Apple. Поэтому в соответствии с этим я использую следующие методы, и все хорошо работает на iOS 5 и 6.
В моем VC я переопределяю следующие методы:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}
Методы для iOS 6, первый метод возвращает поддерживаемую маску ориентации (как показывает их название)
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
второй, который указывает вашему VC, который является предпочтительной ориентацией интерфейса, когда VC будет отображаться.
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
Просто измените портрет для ориентации, которую вы хотите;)
Это решение работает гладко, мне не нравится идея создания макросов и других вещей, которые охватывают это простое решение.
Надеюсь, что эта помощь...
Ответ 4
У меня была та же проблема, 27 просмотров в моем приложении, из которых 26 в портрете и только одна во всех ориентациях (средство просмотра изображений:)).
Добавление макроса в каждый класс и замена навигации не было решением, с которым мне было удобно...
Итак, я хотел сохранить механику UINavigationController в своем приложении и не заменять ее другим кодом.
Что делать:
@1 В делегате приложения в методе didFinishLaunchingWithOptions
if ([[UIDevice currentDevice].systemVersion floatValue] < 6.0)
{
// how the view was configured before IOS6
[self.window addSubview: navigationController.view];
[self.window makeKeyAndVisible];
}
else
{
// this is the code that will start the interface to rotate once again
[self.window setRootViewController: self.navigationController];
}
@2
Поскольку navigationController просто ответит "YES" для авторотации, нам нужно добавить некоторые ограничения:
Расширьте UINavicationController → YourNavigationController и свяжите его в построителе интерфейса.
@3 Отмените "новые функции" от навигационного контроллера.
Поскольку этот класс является обычным только для этого приложения, он может взять на себя ответственность
для этого контроллеры и реагировать на их месте.
-(BOOL)shouldAutorotate {
if ([self.viewControllers firstObject] == YourObject)
{
return YES;
}
return NO;
}
- (NSUInteger)supportedInterfaceOrientations {
if ([self.viewControllers firstObject] == YourObject)
{
return UIINterfaceOrientationMaskLandscape;
}
return UIInterfaceOrientationMaskPortrait;
}
Надеюсь, это поможет вам,
Ответ 5
Из Примечания к выпуску iOS 6:
Теперь контейнеры iOS (например, UINavigationController) не проконсультируют своих детей, чтобы определить, должны ли они авторотировать.
Передаёт ли ваш rootViewController
сообщение shouldAutoRotate
вниз по иерархии ViewController
на ваш VC?
Ответ 6
Я использовал тот же метод, что и OP pre-ios6 (присутствующий и отклоняющий модальный VC), чтобы показать единый контроллер представления в ландшафтном режиме (все остальные в портрете). Он сломался в ios6 с изображением пейзажа VC в портрете.
Чтобы исправить это, я просто добавил предпочтительный методInterfaceOrientationForPresentation в ландшафтном VC. Кажется, теперь отлично работает для os 5 и os 6.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
- (BOOL)shouldAutorotate
{
return NO;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeLeft;
}
Ответ 7
Эй, ребята, попробовав множество разных возможных решений, без успеха, я пришел со следующим решением, надеюсь, что это поможет!.
Я приготовил рецепт:).
Проблема:
вам нужно изменить ориентацию viewcontrollers с помощью navigationcontroller в ios 6.
Решение:
![navigation suggested]()
шаг 1. один начальный UIviewcontroler для запуска модальных segues в ландшафт и портрет UInavigationControllers как изображение показывает....
глубже в UIViewController1 нам нужны 2 segues действия по глобальной переменной в Appdelegate....
-(void)viewDidAppear:(BOOL)animated{
if([globalDelegate changeOrientation]==0){
[self performSegueWithIdentifier:@"p" sender:self];
}
else{
[self performSegueWithIdentifier:@"l" sender:self];
}
}
также нам нужен обратный путь к портрету & | пейзаж....
- (IBAction)dimis:(id)sender {
[globalDelegate setChangeOrientation:0];
[self dismissViewControllerAnimated:NO completion:nil];
}
шаг 2. первые нажатые UiViewControllers на каждом NavigationController идут с...
-(NSUInteger)supportedInterfaceOrientations{
return [self.navigationController supportedInterfaceOrientations];
}
-(BOOL)shouldAutorotate{
return YES;
}
Шаг 3. Мы перезаписываем метод supportedInterfaceOrientations в подклассе UInavigationController....
в вашем customNavigationController у нас есть.....
-(NSUInteger)supportedInterfaceOrientations{
if([self.visibleViewController isKindOfClass:[ViewController2 class]]){
return UIInterfaceOrientationMaskPortrait;
}
else{
return UIInterfaceOrientationMaskLandscape;
}
}
Шаг 4. На раскадровке или по коду установите флажок FullScreenLayout на yes, как на портретные, так и на ландшафтные uinavigationcontrollers.
Ответ 8
Попробуйте выполнить переход на UINavigationController
, который использует категорию или подклассифицирован для указания желаемой ориентации, а затем перейдите к требуемому VC. Подробнее здесь.
Ответ 9
В качестве альтернативы вы можете сделать то же самое с использованием блоков:
UIViewController *viewController = [[UIViewController alloc] init];
viewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:viewController animated:NO completion:^{
[self dismissViewControllerAnimated:NO completion:nil];
}];
Кроме того, вызовите его перед нажатием нового представления.
Ответ 10
Перейдите к файлу Info.plist и внесите изменения ![enter image description here]()
Ответ 11
У меня была та же проблема. Если вы хотите заставить определенный контроллер представлений отображаться в альбомной ориентации, сделайте это прямо перед тем, как вставить его в стек навигации.
UIInterfaceOrientation currentOrientation = [[UIApplication sharedApplication] statusBarOrientation];
if (currentOrientation == UIInterfaceOrientationPortrait ||
currentOrientation == UIInterfaceOrientationPortraitUpsideDown)
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeLeft];
UIViewController *vc = [[UIViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
[vc release];
Ответ 12
Я решил это, подклассифицировав UINavigationController и переопределив поддерживаемые интерфейсные элементы навигационного контроллера следующим образом:
- (NSUInteger)supportedInterfaceOrientations
{
return [[self topViewController] supportedInterfaceOrientations];
}
Все контроллеры, реализованные с поддержкой встроенных указателей с их желаемыми ориентациями.
Ответ 13
Я использовал следующее решение. В одном контроллере представления, который имеет другую ориентацию, чем все остальные, я добавил проверку ориентации в методе prepareForSegue. Если диспетчеру назначения назначения требуется другая ориентация интерфейса, чем отображаемый текущий, тогда отправляется сообщение, которое заставляет интерфейс вращаться во время синхронизации.
#import <objc/message.h>
...
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if(UIDeviceOrientationIsLandscape(self.interfaceOrientation))
{
UIInterfaceOrientation destinationOrientation;
if ([[segue destinationViewController] isKindOfClass:[UINavigationController class]])
{
UINavigationController *navController = (UINavigationController *)[segue destinationViewController];
destinationOrientation = [navController.topViewController preferredInterfaceOrientationForPresentation];
} else
{
destinationOrientation = [[segue destinationViewController] preferredInterfaceOrientationForPresentation];
}
if ( destinationOrientation == UIInterfaceOrientationPortrait )
{
if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)])
{
objc_msgSend([UIDevice currentDevice], @selector(setOrientation:), UIInterfaceOrientationPortrait );
}
}
}
}