iPhone - Работа с ориентацией и несколькими видами - PullRequest
4 голосов
/ 03 июля 2010

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

Итак, я создал приложение Critical Mass Typer. Это игра на машинке, использующая клавиатуру в качестве основного метода управления. Слова движутся к центру экрана, где у вас есть ядро. Вы вводите слово и уносите слово, прежде чем оно достигнет вашего ядра. Если в ваше ядро ​​попадет 4 слова, вы достигнете критической массы и взорвитесь (игра окончена).

Теперь я хотел иметь возможность поддерживать как альбомный, так и портретный режим в игре. Я думал об этом заранее и разработал свои классы так, чтобы их было легко реализовать. Настройка игры для этого не была проблемой. Правильное вращение видов было.

Одна вещь, которая возникла довольно быстро, заключалась в том, что любое представление, которое возвращает NO для метода shouldAutorotateToInterfaceOrientation контроллера представления, отменяет возврат его подпредставлений.

Итак, мой главный контроллер вида (CriticalMassViewController) управляет запуском / меню игры и добавляет в качестве подпредставления контроллер вида, который запускает игровой режим (CMGameViewController). Я только хочу, чтобы мой основной контроллер вида находился в ландшафтном режиме, потому что, если я поверну его, анимация / кнопки будут все сбоку. Мне бы пришлось создать другой вид или изменить положение всего на экране, если бы я хотел, чтобы он был настроен на портретный режим. Тем не менее, мой взгляд на игру должен иметь возможность переключаться. Для этого вы устанавливаете возвращаемое значение в конкретный режим, которым вы хотите, чтобы ваш основной вид был. Затем сообщите вашему игровому виду, чтобы не возвращался режим. После этого зарегистрируйте игровой вид для уведомлений, а затем самостоятельно выполните поворот.

Например: CriticalMassViewController.m:

    -(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}

CMGameViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
    /*GUI setup code was here*/

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

-(void)didRotate:(NSNotification *)nsn_notification {
    UIInterfaceOrientation interfaceOrientation = [[UIDevice currentDevice] orientation];
    /*Rotation Code
    if(interfaceOrientation == UIInterfaceOrientationPortrait) {
        //Portrait setup
    } else if(interfaceOrientation == UIInterfaceOrientationLandscapeRight) {
        //Landscape setup
    }

    */
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
        // Return YES for supported orientations
        return NO; 
    }

Хорошо, так что здесь происходит? Мой основной контроллер вида хочет быть только в режиме LandscapeRight. Таким образом, он остается таким, поскольку он никогда не регистрируется для любой другой ориентации для автоматического поворота. Мой игровой контроллер должен вращаться. Если я использую следующий код для shouldAutorotateToInterfaceOrientation

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
        return (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
    }

ЭТО НЕ БУДЕТ ВРАЩАТЬ, КОГДА IPHONE ИЗМЕНИТ ОРИЕНТАЦИЮ. Это потому, что его супер вид говорит, что он не хочет вращаться. Как только суперпредставление возвращает «нет», подпредставление даже не запрашивается. Таким образом, вместо этого мы, контроллер игровых представлений, просто говорим «Нет», я не хочу автоматически поворачиваться к любому представлению. Затем мы регистрируемся для уведомления об изменении ориентации и вызываем наш собственный метод поворота.

Эти последние биты кода - это то, как вы сами управляете вращением. Вызовите rotateView изнутри didRotate. Обратите внимание, я хочу, чтобы пользователь мог поворачиваться только после выбора сложности, поэтому у меня есть логика внутри моего метода didRotate, чтобы определить, должен ли он вообще вращаться. Комментарии в коде объяснят, почему происходят определенные вещи.

-(void) rotateView:(UIInterfaceOrientation)uiio_orientation {

    /*This line is very important if you are using the keyboard. This was actually the
    largest problem I had during this entire ordeal. If you switch orientations while
    the keyboard is already being displayed, it will stay in landscape orientation. To
    get it to switch to portrait, we have to tell the status bar that its orientation
    has changed. Once you do this, the keyboard switches to portrait*/
    [UIApplication sharedApplication].statusBarOrientation = uiio_orientation;

    //Get the view you need to rotate
    UIView *portraitImageView = self.view;

    /*Check to make sure that you are in an orientation that you want to adjust to. If
    you don't check, you can make your view accidently rotate when the user orientates
    their phone to a position you aren't expecting*/
    if(uiio_orientation == UIInterfaceOrientationPortrait || uiio_orientation == UIInterfaceOrientationLandscapeRight) {
        if(uiio_orientation == UIInterfaceOrientationPortrait) {
                    //This transform rotates the view 90 degrees counter clock wise.
            portraitImageView.transform = CGAffineTransformMakeRotation(-M_PI/2);
        } else if(uiio_orientation == UIInterfaceOrientationLandscapeRight) {
                    //This transform rotates the view back to its original position
            portraitImageView.transform = CGAffineTransformMakeRotation(0);
        }

        CGRect frame = portraitImageView.frame;
        frame.origin.y = 0;
        frame.origin.x = 0;
        frame.size.width = portraitImageView.frame.size.height;
        frame.size.height = portraitImageView.frame.size.width;
        portraitImageView.frame = frame;
    }
}

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

Ответы [ 2 ]

2 голосов
/ 27 января 2011

Пользовательские UIViewControllers не предназначены для размещения на одном экране.Я считаю, что линия Apple - это «один UIViewController на экран».Подобные проблемы изменения ориентации являются одной из главных причин.Это понятная «ошибка», и в некоторых случаях я испытываю желание сделать это сам: искушение состоит в том, чтобы в этом случае использовать UIViewController в качестве загрузчика UIView.Нет никакой реальной причины использовать UIViewController вообще как вложенный или повторно используемый компонент «виджета» на экране, просто чтобы получить его представление, вы не получите никакой выгоды, потому что все эти полезные удобные функции, такие как изменение ориентации, viewWillAppear, viewWillDisappear, не будет автоматически вызываться для вас любым другим UIViewController, кроме вашего собственного!Эти вызовы не являются «широковещательными», а «перенаправляются» из родительского UIViewController в дочерний UIViewController.И если вы напишите свой собственный подкласс UIViewController, вы несете ответственность за передачу любого из этих унаследованных вызовов методов.

Ваш внутренний UIViewController не был «не вызван», потому что внешний UIViewController ответил NO, он не был вызван, потому чтоВы не переадресовали вызов своему вложенному UIViewController самостоятельно.Метод изменения ориентации shouldAutorotateToInterfaceOrientation, как и другие методы viewWill *, не передается всем UIViewControllers, они передаются по иерархии из окна верхнего уровня, из класса в класс.Встроенные контроллеры UIViewControllers, такие как UINavigationControllers и UITabBarControllers, явно передают эти вызовы своим дочерним элементам, поэтому при поступлении они выглядят как трансляция, но когда вы вставляете свой собственный подкласс UINavigationController в иерархию VC, вы должны сами передать эти вызовы любым дочерним элементам.UINavigationControllers.Это то, что вы должны сделать, если вы хотите написать свой собственный «глобальный контроллер VC», например, замену UITabBarController.

0 голосов
/ 10 августа 2012
 if([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortrait || [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown)
        {         
           //for portrait
             NSLog(@"portrait");
        }
        else if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft || [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight)
        {
            // code for landscape orientation      

             NSLog(@"landscape");
        }
...