Подтвердить что ты не робот

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 (тот, который я хочу быть в ландшафте) строка состояния "Нет", ориентация установлена ​​на альбомную.

Любая помощь приветствуется. Благодарю.

4b9b3361

Ответ 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 );
            }
        }
    }
}