iOS 橫豎屏切換解決方案

iOS 橫豎屏切換解決方案

前言

在大多數(shù)項目中,App 的 UI 方向都是豎屏的,所以一般會在 target 中將屏幕方向設(shè)置為只支持豎屏。如下圖

image

而在項目中可能又存在少量的橫屏頁面,或少數(shù)支持多方向的頁面。視頻播放頁,通常都支持自動旋轉(zhuǎn)。在我的項目中就出現(xiàn)這種情況,為了解決這個問題,所以對 UIViewController 進(jìn)行了分類擴(kuò)展。

方案使用

效果

image

默認(rèn)情況下是豎屏轉(zhuǎn)動手機(jī),不跟隨旋轉(zhuǎn),實現(xiàn)支持方向方法后,可以跟隨。

Demo鏈接地址: 前往

引入

使用 Cocoapods

pod 'AutoRotation'

手動

前往項目地址,下載之后將 AutoRotation 文件夾中的文件拖到項目中即可

配置

將工程設(shè)置為只支持豎屏,如圖

image

使用

由于項目中絕大多數(shù)頁面都是豎屏的,所以默認(rèn)情況下,所有的 Controller 將是豎屏展示。在需要橫屏或多方向的 Controller 中實現(xiàn)代碼如下:

#import <AutoRotation/AutoRotation.h>
// 或
#import "AutoRotation.h"

// ViewController.m 中實現(xiàn)下面方法
- (UIInterfaceOrientationMask)ar_supportedOrientations {
    // 支持三個方法
    return UIInterfaceOrientationMaskAllButUpsideDown;
}

通過實現(xiàn)上述方法,即可讓特定的 Controller 支持設(shè)定的方向。

其它 API

/// 轉(zhuǎn)到指定方向
- (void)ar_turnToOrientation:(UIInterfaceOrientationMask)orientation;
/// 轉(zhuǎn)為豎屏
- (void)ar_turnToPortrait;
/// 轉(zhuǎn)為橫屏
- (void)ar_turnToLandscape;
/// 添加特殊處理Controller,用于處理如 AlertContoller 等情況
+ (void)ar_addSpecialControllers:(NSArray<NSString *> *)controllers;
/// 移除特殊處理Controller
+ (void)ar_removeSpecialControllers:(NSArray<NSString *> *)controllers;

解決思路

  1. 使用 Runtime 交互 Appdelegate 和 UIViewController 的相關(guān)方法
  2. 獲取當(dāng)前可見的頂部 Controller 的方法
  3. 將頂部 Controller 支持的方向返回給 Appdelegate 中的 application:supportedInterfaceOrientationsForWindow:方法
  4. 顯示出對應(yīng)用的方向

實現(xiàn)思路其實比較簡單,當(dāng)然中途會有一些問題,代碼實現(xiàn)中對一些異常情況進(jìn)行了處理。

屏幕方向枚舉

iOS 中關(guān)于方向的枚舉有三種

UIInterfaceOrientationMask

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;

UIInterfaceOrientation

typedef NS_ENUM(NSInteger, UIInterfaceOrientation) {
    UIInterfaceOrientationUnknown            = UIDeviceOrientationUnknown,
    UIInterfaceOrientationPortrait           = UIDeviceOrientationPortrait,
    UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
    UIInterfaceOrientationLandscapeLeft      = UIDeviceOrientationLandscapeRight,
    UIInterfaceOrientationLandscapeRight     = UIDeviceOrientationLandscapeLeft
} __TVOS_PROHIBITED;

UIDeviceOrientation

typedef NS_ENUM(NSInteger, UIDeviceOrientation) {
    UIDeviceOrientationUnknown,
    UIDeviceOrientationPortrait,            // Device oriented vertically, home button on the bottom
    UIDeviceOrientationPortraitUpsideDown,  // Device oriented vertically, home button on the top
    UIDeviceOrientationLandscapeLeft,       // Device oriented horizontally, home button on the right
    UIDeviceOrientationLandscapeRight,      // Device oriented horizontally, home button on the left
    UIDeviceOrientationFaceUp,              // Device oriented flat, face up
    UIDeviceOrientationFaceDown             // Device oriented flat, face down
} __TVOS_PROHIBITED;

手動更改屏幕方向

由于方案中并不更改工程設(shè)置,只勾選了豎屏,所以在實現(xiàn)中使用了手動轉(zhuǎn)屏方法。代碼如下:

+ (BOOL)setOrientation:(UIInterfaceOrientationMask)orientation {
    UIInterfaceOrientation interfaceOrientation = [self getOrientationWithOrientationMask:orientation];
    UIInterfaceOrientation currentOrientation = [UIViewController currentOrientation];
    if (currentOrientation == interfaceOrientation) {
        return NO;
    }
    NSLog(@"ar log: interfaceOrientation:%ld", interfaceOrientation);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    [[UIApplication sharedApplication] setStatusBarOrientation:interfaceOrientation animated:NO];
#pragma clang diagnostic pop
    [[UIDevice currentDevice] setValue:@(interfaceOrientation) forKey:@"orientation"];
    return YES;
}

實現(xiàn)

通過上述的基礎(chǔ)及實現(xiàn)思路鋪墊,總體實現(xiàn)起來相對簡單。下面是碰到的一些問題。

topViewController 不是在 keyWindow 上

解決辦法是獲取 Appdelegate 中的 window 的 topViewController

AlertView 和 AlertController

解決辦法是 hook dismissViewControllerAnimated 方法并且將相關(guān)的類名加入到特殊 Controller 列表中,在處理這些特殊 Controller 時,將獲取前一個控制器的方向

具體實現(xiàn)代碼可前往 Git 上查看

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 目錄 一、最讓人糾結(jié)的三種枚舉 二、兩種屏幕旋轉(zhuǎn)的觸發(fā)方式 三、屏幕旋轉(zhuǎn)控制的優(yōu)先級 四、開啟屏幕旋轉(zhuǎn)的全局權(quán)限 ...
    來鬧的閱讀 3,108評論 0 4
  • 第一步 首先保證工程支持橫豎屏 不多說看圖 保證圈紅的地方 打?qū)?58F678EC-EABC-4320-9FCB...
    ylgwhyh閱讀 2,020評論 0 1
  • iOS 中橫豎屏切換的功能,在開發(fā)iOS app中總能遇到。以前看過幾次,感覺簡單,但是沒有敲過代碼實現(xiàn),最近又碰...
    零度_不結(jié)冰閱讀 2,305評論 0 0
  • 概述 寫代碼就是在不斷填坑的過程中慢慢成長,程序員哪有不遇坑的呢? 這篇文章來談?wù)刬OS中橫豎屏切換的一些坑,橫豎...
    jumpingfrog0閱讀 11,512評論 6 21
  • IOS 設(shè)備橫豎屏情況 一般情形 所有界面都支持橫豎屏切換如果App的所有切面都要支持橫豎屏的切換,那只需要勾選【...
    leonardni閱讀 2,072評論 0 0

友情鏈接更多精彩內(nèi)容