Nice programing

단일 UIViewController 만 가로 및 세로 방향으로 회전하도록 허용하는 방법은 무엇입니까?

nicepro 2020. 12. 3. 19:44
반응형

단일 UIViewController 만 가로 및 세로 방향으로 회전하도록 허용하는 방법은 무엇입니까?


내 앱은 iphone기기 (iPhone 4 및 5 모두) 전용이며 ios 6.

내 전체 앱은 portrait모드 만 지원 합니다. 그러나 "라는 하나 개의보기가 ChatView내가 모두 지원하려는", landscapeportrait모드.

필요한 장치 회전을 다음과 같이 설정했습니다.

여기에 이미지 설명 입력

또한 "ChatView"에서 회전을 지원하기 위해 다음 코드를 시도했습니다.

-(BOOL)shouldAutorotate
{
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscape;
}

그러나 그것은 그 뷰를 회전시킬 수 없습니다.

나는 이것을 많이 검색했지만 내 문제에 대한 해결책을 찾을 수 없습니다.

또한 "ChatView"에는 프레임이 프로그래밍 방식으로 설정된 버튼, 텍스트 필드와 같은 개체가 있습니다. 그래서 가로 모드로 모든 개체의 프레임을 설정해야하는지 알고 싶습니다.

제발 도와주세요.

감사.....


하나의 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. 도움이 되길 바랍니다 ..


간단하지만 매우 잘 작동합니다. 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

뷰 컨트롤러는 앱 자체에서 지원하지 않는 위치로 절대 회전하지 않습니다. 가능한 모든 회전을 활성화 한 다음 회전하지 않는 뷰 컨트롤러에서 다음 줄을 입력해야합니다.

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

ChatView에서는 다음과 같아야합니다.

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAll;
}

회전 후 레이아웃을 변경해야하는 경우 하위 뷰에 적절한 변경을 구현해야합니다.

- (void)viewWillLayoutSubviews

사용 self.view.bounds의 현재 크기를 확인하기 view때문에, self.view.frame회전 후 변경되지 않습니다.


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;
    }
}

Ted의 답변은 노르웨이의 Alexander가 언급 한 문제와 잘 맞습니다. 하지만 알렉산더가 설명하는 방식으로 문제가 발생하지 않는다고 생각했습니다.

현재 가로 (모든 방향 활성화 됨) 상태 인 ViewController B가 ViewController A로 다시 돌아 오면 (세로 만 해당) 사용자가 뒤로 버튼을 클릭 한 후 supportedInterfaceOrientationsForWindow가 호출되지 않고 ViewController A가 가로 모드로 종료됩니다.

실제로 사용자가 뒤로 버튼을 클릭 한 후 현재 가로 (모든 방향 활성화 됨) 인 ViewController B가 ViewController A (세로 만 해당)로 돌아 오면 Appdelegate

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;

전화를 받고 있습니다. 하지만 여전히 루트 뷰 컨트롤러는 ViewController B (회전이 활성화 된 뷰 컨트롤러)이고, ViewController B가 여전히 반환하고 있기 때문에 ViewController A는 세로 방향으로 돌아 가지 않습니다.

-(BOOL)shouldAutorotate{

    return YES;
}

따라서 뒤로 버튼을 누르면 ViewController B에서 "shouldAutorotate-> NO"가됩니다. 그러면 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;
}

이 문제의 역사 (현재 = iOS 10 기간)에 대해서는 잘 모르겠지만 2016 년 10 월에 게시 한 가장 쉬운 해결책은 없었습니다 .

이것을 원한다고 가정합니다.

  1. iOS 7 이상 만 지원 (iOS 10 포함)
  2. 일부 뷰 컨트롤러는 모든 방향을 지원해야하고 다른 뷰 컨트롤러는 방향의 하위 집합을 지원해야합니다. 내 말의 예 : 하나의 뷰 컨트롤러는 세로 만 지원해야하고 다른 모든 컨트롤러는 모든 방향을 지원해야합니다.
  3. 모든 뷰 컨트롤러는 회전을 지원하는 경우 자동으로 회전해야합니다 (즉, 뷰 컨트롤러에서이 문제를 해결하는 코드를 원하지 않음).
  4. UINavigationControllerXIB / NIB / Storyboards에 아무것도하지 않고도 s 추가 지원

... 그런 다음 (IMO) 가장 쉬운 해결책은 UINavigationControllerDelegate , 하위 클래스 UINavigationController (위의 가정 4를 위반 함 )를 만드는 것 입니다.

이 문제를 해결했을 때 첫 번째 ViewControllerUINavigationControllerDelegate . 이 뷰 컨트롤러는 자신을 탐색 컨트롤러의 대리자로 설정하고 허용되는 방향을 반환합니다. 필자의 경우 기본값은 모든 방향이 허용되고 세로가 선호되지만 특정 경우에는 세로 만 허용됩니다. 아래 코드는 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
        }
    }

Swift 3 코셔 버전

누군가 문제가있는 경우를 위해 여기에 남겨 두었습니다.

애플의 문서 에는 supportedInterfaceOrientations말합니다 :

사용자가 장치 방향을 변경하면 시스템은 루트 뷰 컨트롤러 또는 창을 채우는 최상위 뷰 컨트롤러에서이 메서드를 호출합니다. 뷰 컨트롤러가 새 방향을 지원하면 창과 뷰 컨트롤러가 새 방향으로 회전합니다. 이 메서드는 뷰 컨트롤러의 shouldAutorotate 메서드가 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전혀 호출되지 않습니다.

여기 있습니다!

하나의 뷰 컨트롤러 만 여러 방향을 지원해야하고 다른 뷰 컨트롤러는 지원하지 않는 반대 문제를 수정해야하는 경우이 컨트롤러를 제외한 모든 뷰 컨트롤러에 대해이 변경을 수행하십시오.

이것이 도움이되기를 바랍니다.


@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를 터뜨리는 데 문제가 있습니다. https://stackoverflow.com/a/15057537/1277350 가로 모드에서 뒤로 누르면 방향 메서드가 호출되지 않으므로 a를 표시하고 닫아서 약간 해킹해야합니다. 모달보기.

그리고 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:^{
            }];
        }];
    }
}

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라고 가정합니다.


다음은 Swift 의 Alexander ( https://stackoverflow.com/posts/25507963/revisions ) 의 답변입니다 .

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
}}

그리고 모든 회전을 허용하려는 ViewController의 경우 다음 함수를 추가합니다.

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

저도 같은 상황이었습니다. 그래서 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

기존 NavigationController 대신이 CustomNavigationController를 사용했습니다.

그런 다음 LandScape Orientation에서 표시해야하는 뷰 컨트롤러 내부에서 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

Inside CustomNavigationController, I presented this view controller, not pushed into Navigation Stack. So the LandScapeView appeared in LandScape Orientation.

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

I did not change anything in the Supported Interface Orientation in Project Settings.


// paste this method in app deligate class

- (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;
}   

If the App is supporting from IOS7 to IOS9 use this code for Orientation:

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

I know this questions is very old but It needs an updated answer. The easiest and most correct way to achieve this result is to enable Portrait and Landscape in your app settings. Then add this code to your app delegate:

 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
}

Dont forget to replace "INSERTYOURVIEWCONTROLLERHERE" with your view controller.

참고 URL : https://stackoverflow.com/questions/17466048/how-to-allow-only-single-uiviewcontroller-to-rotate-in-both-landscape-and-portra

반응형