Swift 支持某個頁面橫豎屏切換與強制橫屏
首先需要清晰幾個概念
-
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()
}
-
這里用了兩個判斷:
判斷當前頁面是橫屏還是豎屏 UIApplication.shared.statusBarOrientation.isLandscape (頁面方向)
判斷當前手機發生了橫屏切換還是豎屏切換: 通知的方法 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)
}
}