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

2017-10-10  本文已影响222人  leonardni

一、几个核心的方法


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实现功能全过程)
不同根视图下控制部分屏幕旋转

上一篇 下一篇

猜你喜欢

热点阅读