美文网首页
IOS 不同根视图下控制部分屏幕旋转

IOS 不同根视图下控制部分屏幕旋转

作者: leonardni | 来源:发表于2017-10-10 15:03 被阅读222次

    一、几个核心的方法


    1.1屏幕旋转方向

    - (BOOL)shouldAutorotate//是否支持旋转屏幕{
        return YES;
    }
    - (NSUInteger)supportedInterfaceOrientations//支持哪些方向{
        return UIInterfaceOrientationMaskPortrait;
    }
    - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation//默认显示的方向{
        return UIInterfaceOrientationPortrait;
    }
    

    方法调用有限制
    官方原文:

    image.png
    1.也就是只有在window 的 rootcontroller 或者 window最上层prensented controller里面使用上面三个函数,用户旋转的时候才能得到调用。
    2.只有shouldAutorotate 返回YES时其他两个函数才能得到调用,返回为NO的时候默认为UIInterfaceOrientationMaskPortrait方向。

    因此要控制某个界面旋转只能在windows 的控制器里面,覆盖以上上个方法,并在supportedInterfaceOrientations 获取你需要旋转的控制器的方向。具体的使用代码下面有讨论根控制器分别为UITabBarControllerUINavigationController的情况。

    1.2 代码切换屏幕方向

    //代码切换屏幕方向
    NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
                [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
    

    1.3 显示旋转横屏时消失的状态栏

    info.plist文件中将 View controller-based status bar appearance 设置为NOapplication:didFinishLaunchingWithOptions:中添加下面代码

    [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];
    [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
    

    如此之后你就会发现消失的状态条又乖乖的回来了。

    1.4 屏幕旋转的几个代理方法

    - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration NS_DEPRECATED_IOS(2_0,8_0, "Implement viewWillTransitionToSize:withTransitionCoordinator: instead") __TVOS_PROHIBITED;
    - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation NS_DEPRECATED_IOS(2_0,8_0) __TVOS_PROHIBITED;
    

    方便控制器对屏幕旋转做出相应的响应:

    image.png

    1.5 监听设备的旋转

    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(onDeviceOrientationChange) name:UIDeviceOrientationDidChangeNotification object:nil];
    
    -(void)onDeviceOrientationChange  
    {  
       
        UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;  
        if (UIDeviceOrientationIsLandscape(orientation)) {  
                [self.view setNeedsLayout];  
                [self.view layoutIfNeeded];  
        }else if (orientation==UIDeviceOrientationPortrait){  
               [self.collectionView reloadData];  
                [self.view setNeedsLayout];  
                [self.view layoutIfNeeded];  
       
        }  
    }  
    

    二、系统支持横屏顺序


    (1) 默认读取plist里面设置的方向(优先级最高)等同于Xcode Geneal设置里面勾选


    861981-58be5bbebac5ecd1.jpeg

    只要在plist或者General设置了单一方向,在工程里面的任何代码都会失效。所以想要旋转屏幕,必须让你的工程支持所旋转的方向。
    (但是这里还有一种方式是把当前控制器的View或者view.layer做transform旋转,但是我认为这并不是真正的旋转屏幕,一点可以证明的就是:状态条并不随着旋转)
    (2)application window设置的级别次之
    (3)然后是UINavigationcontroller
    (4)级别最低的是viewcontroller

    三、设置部分控制器旋转


    具体需求描述如下:
    要求app 推入到TGLivePlayController时,(1)用户点击视频全屏/退出全屏书时,自定义播放view可以做出响应的全屏/16:9显示 (2)用户退出TGLivePlayController时,app自动切换到竖屏状态。

    3.1 根控制器为UINavigationController

    -(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
        return UIInterfaceOrientationPortrait;
    }
    
    - (UIInterfaceOrientationMask)supportedInterfaceOrientations {
        UIViewController *vc = self.visibleViewController;
        if([vc isKindOfClass:[TGLiveVideoController class]]){
            return [vc supportedInterfaceOrientations];
        }else{
            return UIInterfaceOrientationMaskPortrait;
        }
    }
    
    -(BOOL)shouldAutorotate{
        UIViewController *vc = self.visibleViewController;
        return [vc shouldAutorotate];
       
       //也可以这样写只在指定的vc里面响应,只是这样在退出指定的控制器时不能在willdisappear里面还原竖屏。
        if([vc isKindOfClass:[TGLiveVideoController class]]){
            return [vc supportedInterfaceOrientations];
        }
        return NO;
    }
    

    3.2 根视图控制器为TabBarController

    创建NavigationController和TabBarVontroller的category
    这里注意不能在tabbarcontroller的类里写旋转方法 否则以下方法会无效

    UITabBarController+autoRotate.h
    #import <UIKit/UIKit.h>  
      
    @interface UITabBarController (autoRotate)  
    -(BOOL)shouldAutorotate;  
    -(NSUInteger)supportedInterfaceOrientations;  
    @end  
    
    UITabBarController+autoRotate.m
    #import "UITabBarController+autoRotate.h"  
      
    @implementation UITabBarController (autoRotate)  
    -(BOOL)shouldAutorotate{
        return [self.selectedViewController shouldAutorotate];
    }
    
    -(UIInterfaceOrientationMask)supportedInterfaceOrientations{
        return [self.selectedViewController supportedInterfaceOrientations];
    }
    
    -(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
        return [self.selectedViewController preferredInterfaceOrientationForPresentation];
    }
    @end  
    
    UINavigationController+autoRotate.h
    @interface UINavigationController (autoRotate)  
    -(BOOL)shouldAutorotate;  
    -(NSUInteger)supportedInterfaceOrientations;  
    @end  
    
    UINavigationController+autoRotate.m
    -(BOOL)shouldAutorotate{
        return [self.selectedViewController shouldAutorotate];
    }
    
    -(UIInterfaceOrientationMask)supportedInterfaceOrientations{
        return [self.selectedViewController supportedInterfaceOrientations];
    }
    
    -(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
        return [self.selectedViewController preferredInterfaceOrientationForPresentation];
    }
    

    3.3 控制器代码

    TGLiveVideoController.m
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        [self LVSetUpNavItem];
        [self LVSetUpSubviews];
    }
    
    -(void)LVSetUpNavItem{
        self.navigationItem.leftBarButtonItem = nil;//移除原有的统一定制的返回键
        UIButton *LeftItem = [UIButton new];
        LeftItem.frame = CGRectMake(0, 0, 24, 24);
        [LeftItem.imageView setContentMode:UIViewContentModeCenter];
        [LeftItem setImage:[UIImage imageNamed:@"back"] forState:UIControlStateNormal];
        [LeftItem setBackgroundImage:[UIImage imageNamed:@"nav_fanhui"] forState:UIControlStateNormal];
        [LeftItem addTarget:self action:@selector(LVbackBtnClick) forControlEvents:UIControlEventTouchUpInside];
        UIBarButtonItem *customLeftItem = [[UIBarButtonItem alloc] initWithCustomView:LeftItem];
        self.navigationItem.leftBarButtonItem = customLeftItem;
    }
    #pragma mark - 替换统一生成的返回键事件
    -(void)LVbackBtnClick{
        //先旋转后退回
        NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
        [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
        [self.navigationController popViewControllerAnimated:YES];
    }
    
    -(void)viewWillLayoutSubviews{
        [super viewWillLayoutSubviews];
        CGFloat videoWidth = kScreenWidth;
        CGFloat videoHeight = _isFullScreen ? self.view.bounds.size.height : kScreenWidth / 16.0f * 9.0f;
        [self.player setPreviewFrame:CGRectMake(0, 0, videoWidth, videoHeight)];
        
        CGFloat btnW = 60.0f;
        CGFloat btnH = 40.0f;
        CGFloat btnX = CGRectGetMaxX(self.player.previewView.frame) - btnW;
        CGFloat btnY = CGRectGetMaxY(self.player.previewView.frame) - btnH;
        self.btnFullScreen.frame = CGRectMake(btnX, btnY, btnW, btnH);
    }
    
    -(BOOL)shouldAutorotate{
        return YES;
    }
    
    - (UIInterfaceOrientationMask)supportedInterfaceOrientations {
        return UIInterfaceOrientationMaskAllButUpsideDown;
    }
    
    #pragma mark - 旋转代理事件
    - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
                                    duration:(NSTimeInterval)duration{
        _isFullScreen = NO;
        //横屏情况
        if(toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
           toInterfaceOrientation == UIInterfaceOrientationLandscapeRight){
            _isFullScreen = YES;
        }
        self.btnFullScreen.selected = _isFullScreen;
    }
    
    #pragma mark - 全屏点击
    -(void)btnFullScreenClick:(UIButton *)sender{
        BOOL state = !self.isFullScreen;
        if(state){
            NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
            [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
        }else{
            NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
            [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
        }
    
    }
    
    

    Rotation Issues in ios 6

    参考文献:

    iOS指定页面屏幕旋转,手动旋转(某app实现功能全过程)
    不同根视图下控制部分屏幕旋转

    相关文章

      网友评论

          本文标题:IOS 不同根视图下控制部分屏幕旋转

          本文链接:https://www.haomeiwen.com/subject/kdvvyxtx.html