Swift 支持某个页面横竖屏切换与强制横屏

Swift 支持某个页面横竖屏切换与强制横屏

Demo地址

首先需要清晰几个概念

  • UIDeviceOrientation 设备的物理方向

    • UIDeviceOrientation即我们手持的移动设备的Orientation,是一个三围空间,有六个方向
public enum UIDeviceOrientation : Int {

    case unknown

    case portrait // Device oriented vertically, home button on the bottom

    case portraitUpsideDown // Device oriented vertically, home button on the top

    case landscapeLeft // Device oriented horizontally, home button on the right

    case landscapeRight // Device oriented horizontally, home button on the left

    case faceUp // Device oriented flat, face up

    case faceDown // Device oriented flat, face down
}
  • UIInterfaceOrientation 界面的显示方向
    • UIInterfaceOrientation即我们看到的视图的Orientation,可以理解为statusBar所在的方向,是一个二维空间,有四个方向
public enum UIInterfaceOrientation : Int {

    case unknown

    case portrait

    case portraitUpsideDown

    case landscapeLeft

    case landscapeRight
}

支持某个页面横竖屏切换

项目要求是要某个界面能够横竖屏显示,其他界面要竖屏显示

1.打开 General 中的 Device orientation 中的 landscapeLeft 与 landscapeRight

avatar

2.在AppDelegate中设置app支持的方法

这里要设置一个全局变量,判断支持的方向

var blockRotation = Bool()

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        if blockRotation {
            return .allButUpsideDown
        }
        return .portrait
        
}

3.在需要支持横竖屏的控制器中

 let appDelegate = UIApplication.shared.delegate as! AppDelegate

在viewDidLoad或viewWillAppear中

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    appDelegate.blockRotation = true
 }

在viewWillDisAppear中

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    appDelegate.blockRotation = false
    
    //判断退出时是否是横屏
    if UIApplication.shared.statusBarOrientation.isLandscape {
        //是横屏让变回竖屏
        setNewOrientation(fullScreen: false)
    }
    
}

退出时需要回到竖屏的状态

//横竖屏
    func setNewOrientation(fullScreen: Bool) {
        if fullScreen { //横屏
            let resetOrientationTargert = NSNumber(integerLiteral: UIInterfaceOrientation.unknown.rawValue)
            UIDevice.current.setValue(resetOrientationTargert, forKey: "orientation")
            
            let orientationTarget = NSNumber(integerLiteral: UIInterfaceOrientation.landscapeLeft.rawValue)
            UIDevice.current.setValue(orientationTarget, forKey: "orientation")
            
        }else { //竖屏
            let resetOrientationTargert = NSNumber(integerLiteral: UIInterfaceOrientation.unknown.rawValue)
            UIDevice.current.setValue(resetOrientationTargert, forKey: "orientation")
            
            let orientationTarget = NSNumber(integerLiteral: UIInterfaceOrientation.portrait.rawValue)
            UIDevice.current.setValue(orientationTarget, forKey: "orientation")
        }
    }

4.判断页面方向

横竖屏这里已经实现了,难处理的是横竖屏后界面视图的适配
用snapKit布局会方便很多,但有些布局,需要判断当前界面时竖屏还是横屏

//statusBar的朝向
UIApplication.shared.statusBarOrientation.isLandscape
  • statusBarOrientation 有两个属性,isLandscape、isPortrait 用来判断是横屏还是竖屏,这是对页面的判断

在有弹出窗的时候,在窗口弹出时判断是横屏还是竖屏,分别做不同的布局

5.判断设备物理方便改变

//注册通知
        if !UIDevice.current.isGeneratingDeviceOrientationNotifications {
            //生成通知
            UIDevice.current.beginGeneratingDeviceOrientationNotifications()
        }
        NotificationCenter.default.addObserver(self, selector: #selector(handleDeviceOrientationChange(notification:)), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)

实现通知的方法

@objc private func handleDeviceOrientationChange(notification: Notification) {
        
        let orientation = UIDevice.current.orientation
        
        switch orientation {
            
        case .portrait:
            
            /* iOS8之后,横屏UIScreen.main.bounds.width等于竖屏时的UIScreen.main.bounds.height
            
             let ScreenW = UIApplication.shared.statusBarOrientation.isLandscape ? UIScreen.main.bounds.size.height : UIScreen.main.bounds.size.width
             let ScreenH = UIApplication.shared.statusBarOrientation.isLandscape ? UIScreen.main.bounds.size.width : UIScreen.main.bounds.size.height
             
            ScreenW 记录的是屏幕短边的长度
            ScreenH 记录的是屏幕长边的长度
            */
            showLabel.frame = CGRect(x: 0, y: 0, width: ScreenW, height: 20)

        case .landscapeLeft:
            showLabel.frame = CGRect(x: 0, y: 0, width: ScreenW, height: 20)

            
        case .landscapeRight:
            //横屏后做界面的调整的代码
            showLabel.frame = CGRect(x: 200, y: 200, width: 80, height: 20)

            
        default:
            
            break
            
            
        }
    }

最后移除通知

deinit {
        //移除通知
        NotificationCenter.default.removeObserver(self)
        UIDevice.current.endGeneratingDeviceOrientationNotifications()
    }
  • 这里用了两个判断:

    1. 判断当前页面是横屏还是竖屏 UIApplication.shared.statusBarOrientation.isLandscape (页面方向)

    2. 判断当前手机发生了横屏切换还是竖屏切换: 通知的方法 let orientation =UIDevice.current.orientation (设备的方向) 在通知的方法里完成布局

项目中比demo中布局复杂,使用这两个判断结合的方式进行布局

强制横屏

1.关闭 General 中的 Device orientation 中的 landscapeLeft 与 landscapeRight

avatar

2.在AppDelegate中设置app支持的方法

这里要设置一个全局变量,判断支持的方向,这里支持一个方向

var blockRotation = Bool()

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        if blockRotation {
            return .landscapeLeft
        }
        return .portrait
        
}

3. 强制横屏方法

swift移除了NSInvocation, 只能桥接,需要创建桥接文件,注意桥接文件路径

// h文件
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface DeviceTool : NSObject

+ (void)interfaceOrientation:(UIInterfaceOrientation )orientation;

@end


//m文件
#import "DeviceTool.h"

@interface DeviceTool ()

@end

@implementation DeviceTool

+ (void)interfaceOrientation:(UIInterfaceOrientation)orientation{
    if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
        SEL selector = NSSelectorFromString(@"setOrientation:");
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
        [invocation setSelector:selector];
        [invocation setTarget:[UIDevice currentDevice]];
        int val  = orientation;
        // 从2开始是因为0 1 两个参数已经被selector和target占用
        [invocation setArgument:&val atIndex:2];
        [invocation invoke];
    }
}

@end

4.实现横屏

实现的是强制转landscapeLeft方向,与appDelegate中支持的方向一致,这样是否打开系统竖排方向锁定不影响强转方向

@objc func buttonClick(btn:UIButton) {
        btn.isSelected = !btn.isSelected
        if btn.isSelected {
            appDelegate.blockRotation = true
            DeviceTool.interfaceOrientation(.landscapeLeft)

        }else{
            appDelegate.blockRotation = false
            DeviceTool.interfaceOrientation(.portrait)
        }
    }

附上Demo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容