iOS: отключить авторотацию для подпредставления - PullRequest
17 голосов
/ 09 сентября 2011

У меня есть вложенная иерархия представлений для приложения iPad, которая поддерживает изменения ориентации.Это выглядит примерно так:

UIViewController
    UIView
        - UIView
            - UIImageView (disable rotation)
            - UIImageView
            - UIView (disable rotation)
        - UIView
        - UIView
        ...

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

Один из подходов заключается в ручном повороте подпредставлений в пределах willAnimateRotationToInterfaceOrientation:.Это не особенно привлекательно, учитывая, что SDK выполняет ротацию, которую я просто отменил бы.

Есть ли способ просто отключить изменения ориентации для подпредставлений или какой-либо другой метод реструктуризации моей иерархии?

Ответы [ 3 ]

22 голосов
/ 09 сентября 2011

Авторация обрабатывается UIViewController вида (shouldAutorotateToInterfaceOrientation:), поэтому один из подходов состоит в том, чтобы упорядочить иерархию так, чтобы вращающиеся представления управлялись одним контроллером представления, а не вращающиеся представления - другим контроллером представления. Затем оба корневых представления UIViewController необходимо добавить в окно / суперпредставление.

Тонкость здесь заключается в том, что если у вас есть два вида контроллера представления на одном уровне (т.е. добавлены через addSubview:), только первый контроллер представления (обычно rootViewController) окна получит сообщение shouldAutorotateToInterfaceOrientation:.

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

Технические вопросы и ответы Apple QA1688 («Почему мой UIViewController не вращается вместе с устройством?») немного говорит об этой проблеме.


Обновление для iOS 6:

Autorotation теперь использует методы UIViewController shouldAutorotate и supportedInterfaceOrientations. shouldAutorotate возвращает YES по умолчанию, но помните, что контроллер представления, отличный от rootViewController, чье представление является прямым подпредставлением окна, в любом случае НЕ получит обратные вызовы вращения.


Пример кода для iOS 6:

Создайте новый проект, используя шаблон «Single View Application», и убедитесь, что установлен флажок «Use Storyboards». Мы будем использовать предоставленный класс ViewController в качестве контроллера вращающегося представления (переименуйте его, если хотите!), И создадим второй подкласс UIViewController с именем NonRotatingViewController. Хотя этот контроллер представления никогда даже не получит обратные вызовы вращения, для полноты и ясности добавьте следующий код в NonRotatingViewController.m:

- (BOOL)shouldAutorotate
{
    return NO;
}

В файле MainStoryboard перетащите новый объект контроллера представления, установите для него класс NonRotatingViewController и установите для идентификатора раскадровки значение "NonRotatingVC". Пока вы там, измените цвет фона представления контроллера с вращающимся видом на прозрачный (под ним будет добавлен не вращающийся вид) и добавьте метку к каждому виду. В AppDelegate.m добавьте следующий код:

#import "NonRotatingViewController.h"

// ...
// ...

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
    NonRotatingViewController *nonRotatingVC = [mainStoryboard instantiateViewControllerWithIdentifier:@"NonRotatingVC"];
    [self.window addSubview:nonRotatingVC.view];
    return YES;
}

Это просто создание экземпляра не вращающегося контроллера представления и добавление его вида непосредственно к окну (на данный момент rootViewController окна уже установлено раскадровкой).

Запустите проект. Вращайте устройство и удивляйтесь, когда одна этикетка вращается, а другая остается неподвижной!


Пример кода до iOS 6:

Я сделал это в новом проекте - новое приложение на основе View будет работать нормально. Добавьте два новых контроллера представления: RotatingViewController и NonRotatingViewController. Внутри каждого из них я просто добавил метку, чтобы описать, должен ли вид вращаться или нет. Добавьте следующий код:

RotatingViewController.m

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return YES;
}


'NonRotatingViewController.m

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    if (interfaceOrientation == UIInterfaceOrientationPortrait) {    // Or whatever orientation it will be presented in.
        return YES;
    }
    return NO;
}


'AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    RotatingViewController *rotating = [[RotatingViewController alloc] initWithNibName:@"RotatingViewController" bundle:nil];
    self.rotatingViewController = rotating;
    [rotating release];

    NonRotatingViewController *nonRotating = [[NonRotatingViewController alloc] initWithNibName:@"NonRotatingViewController" bundle:nil];
    self.nonRotatingViewController = nonRotating;
    [nonRotating release];

    [self.window addSubview:self.rotatingViewController.view];
    [self.window insertSubview:self.nonRotatingViewController.view belowSubview:self.rotatingViewController.view];

    [self.window makeKeyAndVisible];

    return YES;
}

Надеюсь, это поможет.

10 голосов
/ 19 января 2013

Вот другой способ. Просто поместите этот код в ваш viewController viewDidLoad:

    YourAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
        // the view you don't want rotated (there could be a heierarchy of views here):
    UIView *nonRotatingView = [[UIView alloc] initWithFrame:CGRectMake(100,0,30,500)];
    nonRotatingView.backgroundColor = [UIColor purpleColor];

        // make sure self.view and its children are transparent so you can see through to this view that will not be rotated behind self.view.

    [delegate.window insertSubview:nonRotatingView  belowSubview:self.view];

        // you can't put it in the front using:
        //    [delegate.window insertSubview:nonRotatingView aboveSubview:self.view];
        // It will show up the same as before

    // you should declare nonRotatingView as a property so you can easily access it for removal, etc.
4 голосов
/ 08 июля 2013

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

Найти полный код здесь:
https://gist.github.com/ffraenz/5945301

- (void)orientationDidChangeNotificationReceived:(NSNotification *)notification
{
    // find out needed compass rotation
    //  (as a countermeasure to auto rotation)
    float rotation = 0.0;

    if (self.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
        rotation = M_PI;
    else if (self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft)
        rotation = M_PI / 2.0;
    else if (self.interfaceOrientation == UIInterfaceOrientationLandscapeRight)
        rotation = M_PI / (- 2.0);

    // rotate compass without auto rotation animation
    //  iOS rotation animation duration is 0.3
    //  this excludes the compassView from the auto rotation
    //  (same effect as in the camera app where controls do rotate and camera viewport don't)
    [UIView animateWithDuration:0.3 animations:^(void) {
        self.compassView.transform = CGAffineTransformMakeRotation(rotation);
    }];
}
...