iOS竖屏App强制某一部分横屏

前言

很长时间没有更新,原因不多说(因为懒),最近比较清闲,想起来写一篇文章来说一下iOS横竖屏轻松切换的过程。 有些需求整体的App只支持竖屏,但是只需要某一部分页面支持横屏,许多的视频类的App都要在竖屏的情况下进行横屏播放,当然还有很多的奇葩需求要横屏来进行实现。

废话少说,进主题

创建项目,App的方向只需要勾选Portrait就行(其实可以不用勾,但是能有几个项目中不勾的呢,我们还是勾上吧)。

勾选方向

前面说可以不勾选因为我们要在AppDelegate中,重写这个方法, 应用程序启动的时候会调用这个方法来给App所需要的屏幕方向:

- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
    if([ScreenDirectionManager manager].islandscape) {
        return UIInterfaceOrientationMaskLandscape;
    }else {
        return UIInterfaceOrientationMaskAll;
    }
    
}

其中UIInterfaceOrientationMask是一个NS_OPTIONS, 我们可以随意组合,虽然其中有一些组合好的,但是万一不满足产品的奇葩需求呢,对不对,要提前留一手。

typedef NS_OPTIONS(NSUInteger, UIInterfaceOrientationMask) {
    UIInterfaceOrientationMaskPortrait = (1 << UIInterfaceOrientationPortrait),
    UIInterfaceOrientationMaskLandscapeLeft = (1 << UIInterfaceOrientationLandscapeLeft),
    UIInterfaceOrientationMaskLandscapeRight = (1 << UIInterfaceOrientationLandscapeRight),
    UIInterfaceOrientationMaskPortraitUpsideDown = (1 << UIInterfaceOrientationPortraitUpsideDown),
    UIInterfaceOrientationMaskLandscape = (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),
    UIInterfaceOrientationMaskAll = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown),
    UIInterfaceOrientationMaskAllButUpsideDown = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),
} __TVOS_PROHIBITED;

意思内容不用多解释,应该都能知道什么意思。

其中ScreenDirectionManager这个类控制屏幕是否横屏,是一个单例就一个属性是否需要横屏,比较简单。

@interface ScreenDirectionManager : NSObject

+ (instancetype)manager;

@property (nonatomic, assign, getter=islandscape) BOOL landscape;

@end

如果你的App不包括导航栏(UINaviagtionController)或者(UITabbarController),你只需要重写UIViewController里面的三个方法就行,这三个方法是:

//  返回bool值,决定Controller是否自动旋转
-(BOOL)shouldAutorotate
//返回一个Controller支持的方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
//返回现在正在显示的用户界面方向
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation

但是一般的应用至少有个导航栏吧,所以呢你还需要自定义导航栏(UINavigationController),然后在导航栏里面重写这三个方法,如果不重写,就无法达到你想要的效果,感觉就像这个屏幕方向具有传递的性质。但是我感觉UITabbarController的情况应该少数,我这里不讨论这个情况,下次有空再补上,但是我感觉原理应该是一样的,有兴趣的可以自己试一下。

导航栏的屏幕方向和旋转性质要和导航栏最上层的Controller保持一致,所以自定义导航栏重写的三个方法是这样的:

-(BOOL)shouldAutorotate {
    return [[self.viewControllers lastObject] shouldAutorotate];
}

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

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

ViewController中,重写上述的三个方法,返回自己想要的方向,那个改Controller只能是返回的方向,例如:

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return UIInterfaceOrientationPortrait;
}

- (BOOL)shouldAutorotate {
    return YES;
}

在第二个页面中,也就是跳转的页面中,重写上述的三个方法,返回自己想要的方向,然后在viewWillAppear方法中设定将单例的属性方向改变,然后根据UIDeviceorientation这个属性,根据KVC,强制设置方向,如下;

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [ScreenDirectionManager manager].landscape = YES;
    if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
//写这句话的目的是保证后面的一句话产生作用,具体不明白为什么,但是不加上会出现bug。有明白的可以告知一下。
        [[UIDevice currentDevice] setValue:@(UIDeviceOrientationUnknown) forKey:@"orientation"];
        [[UIDevice currentDevice] setValue:@(UIDeviceOrientationLandscapeLeft) forKey:@"orientation"];
    }
    
}

还需要在viewWillDisappear中,将单例的横竖屏属性改变回来,因为supportedInterfaceOrientations这个方法会触发AppDelegate中的方向支持方法。

结论

文章描述的不太清楚的,欢迎留言讨论。Demo

你可能感兴趣的:(iOS竖屏App强制某一部分横屏)