当前位置: 亚洲城ca88 > ca88 > 正文

不等根视图下决定部分显示器旋转,以及横屏形

时间:2019-09-15 04:12来源:ca88
相信很多APP大多数页面都是竖屏,而只有部分页面会旋转,播放器是其代表之一。 一、几个核心的方法 rootViewController为UITabBarController的情况下 建议创建一个UITabBarController的公共父类

ca88 1

相信很多APP大多数页面都是竖屏,而只有部分页面会旋转,播放器是其代表之一。

一、几个核心的方法


rootViewController为UITabBarController的情况下 建议创建一个UITabBarController的公共父类 在里面实现如下代理方法

ca88 2

preferredInterfaceOrientationForPresentation 打开时当前界面的朝向

shouldAutorotate 是否支持旋转

supportedInterfaceOrientations 所支持的旋转方向

return返回的为当前选中 tabar 的支援情况

在 tabbar 中放UINavigationController后 还需要在 UINavigationController父类中实现如下

ca88 3

然后如果某个界面想支持屏幕旋转 只需要在Controller里面重写写方法即可

ca88 4

需要在 如下方法中新加

- application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait];//此方法

....

}

这样就会解决横屏模式下打开 APP 产生的一些问题

(情况二 容易出现的一些问题为:当你在didFinishLaunchingWithOptions中 加载了另一个 window 的时候需要在自己建的 window 中也遵守屏幕旋转的几个代理方法 不然横屏模式下打开APP布局依然会乱)

有问题请留言 TUT (编辑于 2018.09.03)

但是工程的Landscape Left 和Landscape Right去掉,则部分页面也不支持旋转,Landscape Left 和Landscape Right开启又导致默认是的转屏,所以我们需要自己来实现逻辑控制界面是否可转并且还要默认是竖屏

1.1屏幕旋转方向

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

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

ca88 5

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、默认的所有页面是竖屏的

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;

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

ca88 6

image.png

2、部分页面可以通过设置开关支持旋转。

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设置里面勾选

ca88 7

861981-58be5bbebac5ecd1.jpeg

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

1、首先我们先想到的是将plist的Landscape Left 和Landscape Right关掉,但是关掉了工程的配置,在单个页面开启旋转是行不通的。

三、设置部分控制器旋转


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

2、那我们就不靠工程的配置,自己写逻辑来控制,在iOS6之后AppDelegate里面有个

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

- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window

3.2 根视图控制器为TabBarController

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

该方法在每次屏幕旋转的时候可以设置页面是否转屏。

UITabBarController autoRotate.h
#import <UIKit/UIKit.h>  

@interface UITabBarController (autoRotate)  
-(BOOL)shouldAutorotate;  
-(NSUInteger)supportedInterfaceOrientations;  
@end  

新建个工具类AutoRotate.h具体代码逻辑如下

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  

(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {

if (window != nil) {

UIWindow *w = [UIApplication sharedApplication].delegate.window;

return [self orientationFromWindow:w];

}

return UIInterfaceOrientationMaskPortrait;

}

(UIInterfaceOrientationMask)orientationFromWindow:(UIWindow *)window {

UIViewController *rootViewController = window.rootViewController;

if ([rootViewController isKindOfClass:[UITabBarController class]]) {

UITabBarController *tabar = (UITabBarController *)rootViewController;

//获取当前选择的navigationController

UINavigationController *ca88,nav = tabar.selectedViewController;

//获取当前显示的viewController

UIViewController *topViewController = nav.topViewController;

//获取当前界面的presentedViewController

UIViewController *presentedViewController = topViewController.presentedViewController;

//正在显示的viewController

UIViewController *showViewController = topViewController;

//如果有presentedViewController,则用

if (presentedViewController != nil) {

//TODO 这个判断有待测试 下面的情况用的不多

if ([presentedViewController isKindOfClass:[UINavigationController class]]) {

UINavigationController *nav = (UINavigationController *)presentedViewController;

UIViewController *topVC  = nav.topViewController;

showViewController = topVC;

} else {

showViewController = presentedViewController;

}

}

//默认不转屏

UIInterfaceOrientationMask orientation = UIInterfaceOrientationMaskPortrait;

BOOL shouldAutorotate = [self shouldAutorotate:showViewController];

//如果可转屏,获取转屏方向

if (shouldAutorotate) {

orientation = [showViewController supportedInterfaceOrientations];

} else {

UIInterfaceOrientation statusBarOrientation = [UIApplication sharedApplication].statusBarOrientation;

switch (statusBarOrientation) {

case UIInterfaceOrientationLandscapeLeft:

orientation = UIInterfaceOrientationMaskLandscapeLeft;

break;

case UIInterfaceOrientationLandscapeRight:

orientation = UIInterfaceOrientationMaskLandscapeRight;

break;

default:

orientation = UIInterfaceOrientationMaskPortrait;

break;

}

}

return orientation;

}

return UIInterfaceOrientationMaskPortrait;

}

(BOOL)shouldAutorotate:(UIViewController *)showViewController {

//从方法列表中判断是否实现了shouldAutorotate方法(因为ViewController里面的实现不靠谱)

Class rotateClass = [showViewController class];

while (rotateClass != nil && rotateClass != [UIViewController class] && [rotateClass isSubclassOfClass:[UIViewController class]]) {

unsigned int methodCount;

Method *methods = class_copyMethodList(rotateClass, &methodCount);

for (unsigned int i = 0; i < methodCount; i ) {

SEL sel = method_getName(methods[i]);

if (sel == @selector(shouldAutorotate)) {//如果实现了方法,判断是否可转屏

return [showViewController shouldAutorotate];

}

}

rotateClass = [rotateClass superclass];

}

return NO;

}

UINavigationController autoRotate.m
-(BOOL)shouldAutorotate{
    return [self.selectedViewController shouldAutorotate];
}

-(UIInterfaceOrientationMask)supportedInterfaceOrientations{
    return [self.selectedViewController supportedInterfaceOrientations];
}

-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
    return [self.selectedViewController preferredInterfaceOrientationForPresentation];
}

3.3 控制器代码

如果你的APP是tabbar布局可以直接用,如果不是则需要更改rootViewController的转换

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

编辑:ca88 本文来源:不等根视图下决定部分显示器旋转,以及横屏形

关键词: 亚洲城ca88