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

Как разрешить только один UIViewController вращаться в направлении "Пейзаж" и "Портрет"?

Мое приложение предназначено только для устройства iphone (как для iphone 4 и 5), так и для поддержки только ios 6.

Все мое приложение поддерживает только режим portrait. Но есть одно представление под названием "ChatView", которое я хочу поддерживать как в режимах landscape, так и portrait.

Я установил необходимые вращения устройства следующим образом:

enter image description here

Я также пробовал следующий код для поддержки вращения в "ChatView" -

-(BOOL)shouldAutorotate
{
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscape;
}

Но он не мог повернуть этот вид.

Я много искал для этого, но не смог найти решение для своей проблемы.

А также в "ChatView" есть некоторые объекты, такие как кнопки, текстовые поля, чьи кадры заданы программно. Так что я хочу знать, должен ли я также устанавливать кадры всех этих объектов для ландшафтного режима?

Пожалуйста, помогите мне.

Спасибо.....

4b9b3361

Ответ 1

Я думаю, что если вы хотите поддерживать только один поворот viewcontroller, это невозможно, так как приложение будет следовать настройкам, установленным вами в файле .plist. Альтернативой, которую вы можете использовать, является поддержка вашего приложения как для пейзажа, так и для портрета, затормозить вращение всех зрителей до портрета, за исключением просмотра чата.

ИЗМЕНИТЬ

В подкласс UINavigationController создайте новый файл с именем, например. CustomNavigationController и сделать его подклассом UINavigationController.

.h файл

#import <UIKit/UIKit.h>

@interface CustomNavigationController : UINavigationController

@end

.m файл

#import "CustomNavigationController.h"

@interface CustomNavigationController ()

@end


@implementation CustomNavigationController

-(BOOL)shouldAutorotate
{
    return NO;
}

-(UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAll;
}


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

@end

Задайте класс вашего UINavigationController в вашем основном классе xib как CustomNavigationController. Надеюсь, это поможет ypu..

Ответ 2

Простой, но он работает очень хорошо. IOS 7.1 и 8

AppDelegate.h

@property () BOOL restrictRotation;

AppDelegate.m

-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if(self.restrictRotation)
    return UIInterfaceOrientationMaskPortrait;
else
    return UIInterfaceOrientationMaskAll;
}

ViewController

-(void) restrictRotation:(BOOL) restriction
{
    AppDelegate* appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
    appDelegate.restrictRotation = restriction;
}

viewDidLoad

[self restrictRotation:YES]; or NO

Ответ 3

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

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

В ChatView это должно быть:

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAll;
}

Если вам нужно изменить макет после поворота, вы должны реализовать соответствующие изменения в своих подзонах в

- (void)viewWillLayoutSubviews

Используйте self.view.bounds для проверки текущего размера view, так как self.view.frame не изменяется после поворотов.

Ответ 4

для конкретного viewcontroller.m, который вы хотите повернуть

добавьте этот метод:

- (BOOL)canAutoRotate
{
    return YES;
}

затем внутри вашего AppDelegate.m

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    UIViewController *currentViewController = [self topViewController];

    if ([currentViewController respondsToSelector:@selector(canAutoRotate)]) {
        NSMethodSignature *signature = [currentViewController methodSignatureForSelector:@selector(canAutoRotate)];

        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];

        [invocation setSelector:@selector(canAutoRotate)];
        [invocation setTarget:currentViewController];

        [invocation invoke];

        BOOL canAutorotate = NO;
        [invocation getReturnValue:&canAutorotate];

        if (canAutorotate) {
            return UIInterfaceOrientationMaskAll;
        }
    }

    return UIInterfaceOrientationMaskPortrait;
}

- (UIViewController *)topViewController
{
    return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}

- (UIViewController *)topViewControllerWithRootViewController:(UIViewController *)rootViewController
{
    if ([rootViewController isKindOfClass:[UITabBarController class]]) {
        UITabBarController* tabBarController = (UITabBarController*)rootViewController;
        return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
    } else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
        UINavigationController* navigationController = (UINavigationController*)rootViewController;
        return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
    } else if (rootViewController.presentedViewController) {
        UIViewController* presentedViewController = rootViewController.presentedViewController;
        return [self topViewControllerWithRootViewController:presentedViewController];
    } else {
        return rootViewController;
    }
}

Ответ 5

Тед-ответ хорошо работает с вопросом, упомянутым Александром из Норвегии. Но я подумал, что вопрос не происходит так, как объяснил Александр,

Когда ViewController B, который в настоящее время находится в ландшафте (All ориентации включены) возвращается обратно в ViewController A. (Портрет только) после того, как пользователь нажимает кнопку "Назад", supportInterfaceOrientationsForWindow не вызывается и ViewController A заканчивается в ландшафте

Фактически, когда ViewController B, который в настоящее время находится в ландшафте (все ориентации включены), возвращается обратно в ViewController A (только портрет) после того, как пользователь нажимает кнопку "Назад", Appdelegate

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;

вызывается. Но все же контроллер корневого представления - ViewController B (этот контроллер с поддержкой вращения включен), ViewController A не возвращается к портретной ориентации, поскольку ViewController B все еще возвращает

-(BOOL)shouldAutorotate{

    return YES;
}

Итак, когда вы нажмете кнопку возврата назад, "shouldAutorotate → NO" в ViewController B. Затем ViewController A перейдет в портретную ориентацию. Это то, что я сделал

@property (nonatomic, assign) BOOL canAutoRotate;

#pragma mark - Public methods
- (BOOL)canAutoRotate
{
    return _canAutoRotate;
}

#pragma mark - Button actions
- (void)backButtonPressed:(UIButton *)sender {
    _canAutoRotate = NO;
   (...)
}

#pragma mark - Init
- (id)init{
    if(self=[super init]) {
        _canAutoRotate = YES;
    }
    return self;
}

Ответ 6

Swift 3 кошерная версия

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

Документация Apple для supportedInterfaceOrientations гласит:

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

В нескольких словах вы должны переопределить supportedInterfaceOrientations в корневом контроллере представления, чтобы он возвращал значение для своего верхнего дочернего контроллера представления и значение по умолчанию в противном случае.

Что вы должны сделать, это проверить, поддерживает ли приложение все режимы (перейдите к разделу Информация о развертывании в общих настройках целей или Info.plist), выясните класс вашего корневого контроллера представления. Это может быть универсальный UIViewController, UINavigationController, UITabBarController или некоторый пользовательский класс. Вы можете проверить это следующим образом:

dump(UIApplication.shared.keyWindow?.rootViewController)

Или любым другим способом, который вам нравится.

Пусть это будет какой-то CustomNavigationController. Таким образом, вы должны переопределить supportedInterfaceOrientations следующим образом:

class CustomNavigationController: UINavigationController {

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return topViewController?.supportedInterfaceOrientations ?? .allButUpsideDown
    }
}

В любом контроллере представления, который должен поддерживать только книжную ориентацию, например, переопределить supportedInterfaceOrientations следующим образом:

class ChildViewController: UIViewController {

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .portrait
    }
}

Тогда не забудьте проверить, должен ли shouldAutorotate контроллер представления и самый верхний представленный контроллер представления уже вернуть true. Если нет, добавьте это в определения классов:

override var shouldAutorotate: Bool {
    return true
}

В противном случае supportedInterfaceOrientations не будет вызываться вообще.

Ну вот!

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

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

Ответ 7

На основе ответа @iAnum я включил определение авторотации и определения класса UIViewController.

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

У меня был только один вид поддержки ландшафта, поэтому я просто закодировал его в настраиваемом контроллере представления навигации:

-(BOOL)shouldAutorotate
{
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations
{
    //Access the current top object.
    UIViewController *viewController = [self.viewControllers lastObject];
    //Is it one of the landscape supported ones?
    if ([viewController isMemberOfClass:[SpecialViewController class]]) {
        return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
    } else
        return UIInterfaceOrientationMaskPortrait;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    //Access the current top object.
    UIViewController *viewController = [self.viewControllers lastObject];
    //Is it one of the landscape supported ones?
    if ([viewController isMemberOfClass:[SpecialViewController class]]) {
        return interfaceOrientation;
    } else
        return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}

Здесь обсуждаются проблемы, связанные с VC, которые обсуждаются здесь fooobar.com/questions/67650/..., где отбрасывание назад в то время как в ландшафте даже не вызовет методы ориентации, поэтому вы должны взломать его немного, показывая и отклоняя модальный вид.

И тогда просто помните, что если вы хотите, чтобы willShowViewController запускался, вам нужно установить self.delegate = self и добавить UINavigationControllerDelegate в свой пользовательский контроллер навигации вместе с приведенным ниже кодом.

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return UIInterfaceOrientationPortrait;
}

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    UIApplication* application = [UIApplication sharedApplication];
    if (application.statusBarOrientation != UIInterfaceOrientationPortrait)
    {
        UIViewController *c = [[UIViewController alloc]init];
        [c.view setBackgroundColor:[UIColor clearColor]];
        [navigationController presentViewController:c animated:NO completion:^{
            [self dismissViewControllerAnimated:YES completion:^{
            }];
        }];
    }
}

Ответ 8

создайте подкласс UINavigationController следующим образом:

MyNavigationController.h

#import <UIKit/UIKit.h>

@interface MyNavigationController : UINavigationController

@end

MyNavigationController.m

#import "MyNavigationController.h"
#import "ServicesVC.h"

@implementation MyNavigationController

-(BOOL)shouldAutorotate{

    return YES;
}

-(NSUInteger)supportedInterfaceOrientations{

    if ([[self.viewControllers lastObject] isKindOfClass:[ServicesVC class]]) {
        return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
    }

    return UIInterfaceOrientationMaskAll;
}

@end

Предполагая, что ваш диспетчер представлений назван: ServicesVC

Ответ 9

Вот ответ Александра (https://stackoverflow.com/posts/25507963/revisions) в Swift:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {

    var currentViewController: UIViewController? = self.topViewController()
    if currentViewController != nil && currentViewController!.canAutoRotate() {
        return Int(UIInterfaceOrientationMask.All.rawValue)
    }
    return Int(UIInterfaceOrientationMask.Portrait.rawValue)


}

func topViewController() -> UIViewController? {
    if UIApplication.sharedApplication().keyWindow != nil
    {
        return self.topViewControllerWithRootViewController(UIApplication.sharedApplication().keyWindow!.rootViewController!)
    }
    return nil
}

func topViewControllerWithRootViewController(rootViewController: UIViewController?) -> UIViewController? {
    if rootViewController == nil {
        return nil
    }
    if rootViewController!.isKindOfClass(UITabBarController) {
        var tabBarController: UITabBarController = (rootViewController as? UITabBarController)!
        return self.topViewControllerWithRootViewController(tabBarController.selectedViewController)
    }
    else {
        if rootViewController!.isKindOfClass(UINavigationController) {
            var navigationController: UINavigationController = (rootViewController as? UINavigationController)!
            return self.topViewControllerWithRootViewController(navigationController.visibleViewController)
        }
        else {
            if (rootViewController!.presentedViewController != nil) {
                var presentedViewController: UIViewController = rootViewController!.presentedViewController!
                return self.topViewControllerWithRootViewController(presentedViewController)
            }
            else {
                return rootViewController
            }
        }
    }
}

Кроме того, вам нужно будет добавить следующий фрагмент в AppDelegate.swift:

extension UIViewController {
func canAutoRotate() -> Bool {
    return false
}}

И для ViewControllers, для которых вы хотите разрешить все вращения, добавьте эту функцию:

override func canAutoRotate() -> Bool {
    return true
}

Ответ 10

Я не уверен в истории этой проблемы (сейчас = iOS 10 таймфрейма), но было простое решение, поскольку я опубликовал это в октябре 2016 года.

Предполагая, что вы хотите:

  • Поддержка iOS 7 и только новых (включая iOS 10)
  • Некоторые контроллеры представлений должны поддерживать все ориентации, другие должны поддерживать поднабор ориентации. Пример того, что я имею в виду: один контроллер просмотра должен поддерживать только портрет, в то время как все остальные должны поддерживать все ориентации
  • Все контроллеры представлений должны автоматически вращаться, если они поддерживают ротацию (это означает, что вы не хотите, чтобы этот код исправлял эту проблему в контроллерах представлений).
  • Поддержка добавления UINavigationController в XIBs/NIBs/Storyboards без необходимости что-либо делать с ними

... тогда (IMO) самым простым решением является сделать UINavigationControllerDelegate, НЕ подкласс UINavigationController (который нарушает предположение 4 выше).

Когда я решил это, я решил сделать мой первый ViewController a UINavigationControllerDelegate. Этот контроллер представления устанавливает себя как делегат контроллера навигации и возвращает, какие ориентации разрешены. В моем случае значением по умолчанию является то, что все ориентации разрешены с предпочтительным портретом, но в одном конкретном случае разрешен только портрет. Код ниже - от Swift 3/XCode 8:

    class iPhoneStartViewController: UIViewController {

        var navInterfaceOrientationMask: UIInterfaceOrientationMask?
        var navInterfaceOrientationPreferred: UIInterfaceOrientation! = .portrait

        override func viewDidLoad() {
            super.viewDidLoad()
            self.navigationController?.delegate = self
        }

        @IBAction func cameraButtonPressed(_ sender: AnyObject) {
            if PermissionsHelper.singleton().photosPermissionGranted() == false {
                self.navInterfaceOrientationMask = nil   // default is: all orientations supported
                self.performSegue(withIdentifier: "segueToPhotoAccess", sender: self)
            } else {
                self.navInterfaceOrientationMask = .portrait // this stops the next view controller from being to rotate away from portrait
                self.performSegue(withIdentifier: "segueToCamera", sender: self)
            }
        }
     }

     // lock orientation to portrait in certain cases only. Default is: all orientations supported
    extension iPhoneStartViewController : UINavigationControllerDelegate {
        public func navigationControllerSupportedInterfaceOrientations(_ navigationController: UINavigationController) -> UIInterfaceOrientationMask {
            if let mask = self.navInterfaceOrientationMask {
                return mask
            } else {
                return .all
            }
        }

        public func navigationControllerPreferredInterfaceOrientationForPresentation(_ navigationController: UINavigationController) -> UIInterfaceOrientation {
            return self.navInterfaceOrientationPreferred
        }
    }

Ответ 11

У меня была такая же ситуация. Поэтому я подклассифицировал UINavigationController в CustomNavigationController, и внутри этого CustomNavigationController я написал

#define IOS_OLDER_THAN_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] < 6.0 )
#define IOS_NEWER_OR_EQUAL_TO_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 6.0 )


#pragma mark - Rotation

#ifdef IOS_OLDER_THAN_6
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
      return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}
#endif
#ifdef IOS_NEWER_OR_EQUAL_TO_6
-(BOOL)shouldAutorotate {
    return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;;
}
#endif

Я использовал этот CustomNavigationController вместо существующего NavigationController.

Затем внутри контроллера представления, который вы должны отображать в ориентации LandScape, говорят LandScapeView, я написал

#pragma mark - Rotation

#ifdef IOS_OLDER_THAN_6

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
    return (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight | toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}

#endif

#ifdef IOS_NEWER_OR_EQUAL_TO_6

-(BOOL)shouldAutorotate {
    return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskLandscapeLeft;
}

#endif

Внутри CustomNavigationController я представил этот контроллер представлений, а не вдвинулся в стек навигации. Итак, LandScapeView появился в ориентации LandScape.

LandScapeView *graph = [[LandScapeView alloc]init....];
[self presentViewController:graph animated:YES completion:nil];

Я ничего не изменил в Ориентация поддерживаемого интерфейса в настройках проекта.

Ответ 12

//вставьте этот метод в класс приложения deligate

- (UIInterfaceOrientationMask)application:(UIApplication )application supportedInterfaceOrientationsForWindow:(UIWindow )window
{
 if ([self.window.rootViewController.presentedViewController isKindOfClass: [_moviePlayerController class]])
  {
   if (self.window.rootViewController.presentedViewController)
        return UIInterfaceOrientationMaskAll;
    else return UIInterfaceOrientationMaskPortrait;
  }
 else return UIInterfaceOrientationMaskPortrait;
}   

Ответ 13

Если приложение поддерживает от IOS7 до IOS9, используйте этот код для ориентации:

#if __IPHONE_OS_VERSION_MAX_ALLOWED < 90000
- (NSUInteger)supportedInterfaceOrientations
#else
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
#endif
{
    if([AppDelegate isPad]) return UIInterfaceOrientationMaskAll;
    else return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
}

Ответ 14

Я знаю, что этот вопрос очень старый, но ему нужен обновленный ответ. Самый простой и правильный путь для достижения этого результата - включить Portrait и Landscape в настройках вашего приложения. Затем добавьте этот код в свой делегат приложения:

 func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {

    if let navigationController = self.window?.rootViewController as? UINavigationController {

        if navigationController.visibleViewController is INSERTYOURVIEWCONTROLLERHERE  {
            return UIInterfaceOrientationMask.All
        }

        else {
            return UIInterfaceOrientationMask.Portrait
        }
    }

    return UIInterfaceOrientationMask.Portrait
}

Не забудьте заменить "INSERTYOURVIEWCONTROLLERHERE" на ваш контроллер просмотра.