iOS 橫豎屏旋轉(zhuǎn)總結(jié)

一顽决、前言

Swift版本 4.0

Xcode版本 9.2

以前接觸到的項(xiàng)目需求中,幾乎都是全豎屏展現(xiàn)界面,所以我也來(lái)得省事,直接在TARGETS中的界面方向選項(xiàng)中只勾選豎屏,這樣就滿足了需求。

但最近的項(xiàng)目中,產(chǎn)品突然增加了一個(gè)需求,需要部分界面支持旋轉(zhuǎn),這才來(lái)研究了一下屏幕旋轉(zhuǎn)的問(wèn)題!

需要緊急解決問(wèn)題的道友直接看3.3

二包斑、屏幕旋轉(zhuǎn)相關(guān)知識(shí)

2.1 三個(gè)方向的理解和聯(lián)系

UIDeviceOrientation: 設(shè)備方向

public enum UIDeviceOrientation : Int {

case unknown

case portrait // 設(shè)備vertically方向, home鍵在下方

case portraitUpsideDown // 設(shè)備vertically方向, home鍵在上方

case landscapeLeft // 設(shè)備horizontally方向, home鍵在右方

case landscapeRight // 設(shè)備horizontally方向, home鍵在左方

case faceUp // 設(shè)備flat方向, 屏幕朝上

case faceDown // 設(shè)備flat方向, 屏幕朝下

}

從設(shè)備方向的命名就能看出來(lái)這個(gè)枚舉的含義,這里指的是物理設(shè)備(即iPhone)的方向干旧。

UIInterfaceOrientation: 界面方向

public enum UIInterfaceOrientation : Int {

case unknown

case portrait

case portraitUpsideDown

case landscapeLeft

case landscapeRight

}

而界面方向指屏幕中顯示內(nèi)容的方向,它的方向和Home鍵的方向是一致的渠欺。仔細(xì)觀察一下屏幕旋轉(zhuǎn)就能理解UIDeviceOrientation和UIInterfaceOrientation了,我們把手機(jī)轉(zhuǎn)向左邊,可以看到界面隨之才轉(zhuǎn)向右邊。

UIInterfaceOrientationMask: 是用來(lái)控制允許轉(zhuǎn)向的方向,對(duì)應(yīng)UIInterfaceOrientation

public struct UIInterfaceOrientationMask : OptionSet {

public init(rawValue: UInt)

public static var portrait: UIInterfaceOrientationMask { get }

public static var landscapeLeft: UIInterfaceOrientationMask { get }

public static var landscapeRight: UIInterfaceOrientationMask { get }

public static var portraitUpsideDown: UIInterfaceOrientationMask { get }

public static var landscape: UIInterfaceOrientationMask { get }

public static var all: UIInterfaceOrientationMask { get }

public static var allButUpsideDown: UIInterfaceOrientationMask { get }

}

2.2 觀察屏幕旋轉(zhuǎn)并作出響應(yīng)

2.2.1 觀察設(shè)備方向并響應(yīng)

// 沒(méi)有生成通知

if !UIDevice.current.isGeneratingDeviceOrientationNotifications {

// 生成通知

UIDevice.current.beginGeneratingDeviceOrientationNotifications()

}

// 鎖定豎屏,依然有效,例如faceUp.

NotificationCenter.default.addObserver(self,

selector: #selector(handleDeviceOrientationChange(notification:)),

name:NSNotification.Name.UIDeviceOrientationDidChange,

object: nil)

@objc private func handleDeviceOrientationChange(notification: Notification) {

// 獲取設(shè)備方向

let orientation = UIDevice.current.orientation

switch orientation {

case .landscapeRight:

// iOS8之后,橫屏UIScreen.main.bounds.width等于豎屏?xí)r的UIScreen.main.bounds.height

print(UIScreen.main.bounds.width)

print("landscapeRight")

default: break

}

}

注銷

deinit {

NotificationCenter.default.removeObserver(self)

UIDevice.current.endGeneratingDeviceOrientationNotifications()

}

2.2.2 觀察界面方向并響應(yīng)

和上面類似不過(guò)觀察的name為

// 鎖定豎屏,無(wú)效,通知方法不會(huì)觸發(fā)

NSNotification.Name.UIApplicationWillChangeStatusBarOrientation

NSNotification.Name.UIApplicationDidChangeStatusBarOrientation

獲取界面方向

let statusBarOrientation = UIApplication.shared.statusBarOrientation

2.2.3 建議

這里建議監(jiān)聽(tīng)界面方向,原因有二:

監(jiān)聽(tīng)設(shè)備方向,會(huì)返回多個(gè)方向,例如portrait和faceUp不沖突莱革。

監(jiān)聽(tīng)設(shè)備方向,上面提到,先是設(shè)備旋轉(zhuǎn),隨之界面旋轉(zhuǎn),這里就有一個(gè)問(wèn)題,我們操作界面時(shí),可能界面還沒(méi)有旋轉(zhuǎn)峻堰。

三、問(wèn)題解決實(shí)戰(zhàn)

需要實(shí)現(xiàn)部分界面可旋轉(zhuǎn),部分界面鎖定豎屏,首先我們需要配置TARGETS中的Device Orientation,這里是總開(kāi)關(guān),默認(rèn)勾選了如圖方向:

如果你確定整個(gè)項(xiàng)目只有豎屏,直接只勾選Protrait完事,不過(guò)像我現(xiàn)在這樣,可能突然一個(gè)需求改變就不得不繼續(xù)適配,哈哈盅视。

這里的配置不要和代碼控制的方向相沖突,不然會(huì)引發(fā)奔潰捐名。

3.1 控制屏幕旋轉(zhuǎn)的函數(shù)

// 默認(rèn)為true

override var shouldAutorotate: Bool {

return true

}

// 支持的旋轉(zhuǎn)方向

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {

return .landscapeLeft

}

// 模態(tài)切換的默認(rèn)方向

override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {

return .landscapeRight

}

這三個(gè)屬性都重寫的UIViewController的屬性。哎,看到模態(tài)切換,這里再給自己挖坑一個(gè),以前研究了一會(huì)模態(tài)切換,只不過(guò)沒(méi)寫成總結(jié),后面會(huì)寫出來(lái)(:闹击。

并且這三個(gè)方法會(huì)受到控制器層級(jí)的影響,也就是如果當(dāng)前控制器配置支持旋轉(zhuǎn),如果他的導(dǎo)航控制器,乃至Tabbar控制器不支持旋轉(zhuǎn),當(dāng)前控制器的配置也不會(huì)生效镶蹋。

3.2 不同根控制器情況下的解決

核心問(wèn)題: 需要旋轉(zhuǎn)的界面是少數(shù),大多界面需要鎖定豎屏。

3.2.1 根控制器為UIViewController

對(duì)應(yīng)Demo配置:

這種情況的APP可以說(shuō)是非常少了,不過(guò)還是對(duì)后面的情況有所幫助。

設(shè)置BaseVC,在其中的配置鎖定豎屏:

class BaseVC: UIViewController {

override var shouldAutorotate: Bool {

return false

}

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {

return .portrait

}

override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {

return .portrait

}

override func viewDidLoad() {

super.viewDidLoad()

}

}

然后其余控制器繼承BaseVC,需要旋轉(zhuǎn)的控制器單獨(dú)再次重寫方法贺归。

3.2.2 根控制器為UINavigationController

對(duì)應(yīng)Demo配置:

我們可以獲取到當(dāng)前顯示層級(jí)的控制器,并拿出它的屬性賦給UINavigationController

class BaseNavC: UINavigationController {

override var shouldAutorotate: Bool {

return self.viewControllers.last?.shouldAutorotate ?? false

}

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {

return self.viewControllers.last?.supportedInterfaceOrientations ?? .portrait

}

override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {

return self.viewControllers.last?.preferredInterfaceOrientationForPresentation ?? .portrait

}

override func viewDidLoad() {

super.viewDidLoad()

}

}

3.2.3 根控制器為UITabBarController

對(duì)應(yīng)Demo配置:

class BaseTabBarC: UITabBarController {

override var shouldAutorotate: Bool {

return self.selectedViewController?.shouldAutorotate ?? false

}

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {

return self.selectedViewController?.supportedInterfaceOrientations ?? .portrait

}

override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {

return self.selectedViewController?.preferredInterfaceOrientationForPresentation ?? .portrait

}

override func viewDidLoad() {

super.viewDidLoad()

}

}

同理,我們只需要獲取當(dāng)前選中的控制器的配置賦給UITabBarController,這樣一層一層就配置好了!

3.3 最簡(jiǎn)單的實(shí)現(xiàn)方式

對(duì)應(yīng)Demo配置:

在查詢屏幕旋轉(zhuǎn)相關(guān)資料的時(shí)候我發(fā)現(xiàn)屏幕旋轉(zhuǎn)時(shí)會(huì)最后調(diào)用Appdelegate中的:

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?)

-> UIInterfaceOrientationMask {

}

然后我立馬想到一個(gè)超級(jí)簡(jiǎn)單的方法,那就是定義一個(gè)全局變量或者緩存一個(gè)bool值來(lái)進(jìn)行判斷,如下:

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?)

-> UIInterfaceOrientationMask {

if isAllowAutorotate {

return [.portrait, .landscapeLeft, .landscapeRight]

}

else {

return .portrait

}

}

然后默認(rèn)isAllowAutorotate這個(gè)全局變量為false,在需要旋轉(zhuǎn)的控制器中:

override func viewWillAppear(_ animated: Bool) {

super.viewWillAppear(animated)

isAllowAutorotate = false

}

override func viewWillDisappear(_ animated: Bool) {

super.viewWillDisappear(animated)

isAllowAutorotate = true

}

}

這樣就不用麻煩的去搞那些繼承什么的了!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末淆两,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子拂酣,更是在濱河造成了極大的恐慌秋冰,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件婶熬,死亡現(xiàn)場(chǎng)離奇詭異剑勾,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)赵颅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門虽另,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人饺谬,你說(shuō)我怎么就攤上這事捂刺。” “怎么了募寨?”我有些...
    開(kāi)封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵族展,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我绪商,道長(zhǎng)苛谷,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任格郁,我火速辦了婚禮腹殿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘例书。我一直安慰自己锣尉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布决采。 她就那樣靜靜地躺著自沧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪树瞭。 梳的紋絲不亂的頭發(fā)上拇厢,一...
    開(kāi)封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音晒喷,去河邊找鬼孝偎。 笑死,一個(gè)胖子當(dāng)著我的面吹牛凉敲,可吹牛的內(nèi)容都是我干的衣盾。 我是一名探鬼主播寺旺,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼势决!你這毒婦竟也來(lái)了阻塑?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤果复,失蹤者是張志新(化名)和其女友劉穎陈莽,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體据悔,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡传透,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了极颓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡群嗤,死狀恐怖菠隆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情狂秘,我是刑警寧澤骇径,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站者春,受9級(jí)特大地震影響破衔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜钱烟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一晰筛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拴袭,春花似錦读第、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至般哼,卻和暖如春吴汪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蒸眠。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工漾橙, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人黔宛。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓近刘,卻偏偏與公主長(zhǎng)得像擒贸,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子觉渴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 本文基于 Swift 3.x介劫,由于 Swift 4.x 在語(yǔ)法規(guī)則上有較大變動(dòng),后續(xù)出一個(gè) Swift 4.x 版...
    emmet7life閱讀 10,128評(píng)論 4 21
  • 1.監(jiān)聽(tīng)屏幕旋轉(zhuǎn)方向 在處理iOS橫豎屏?xí)r案淋,經(jīng)常會(huì)和UIDeviceOrientation座韵、UIInterface...
    彬至睢陽(yáng)閱讀 2,506評(píng)論 1 6
  • 第一步 首先保證工程支持橫豎屏 不多說(shuō)看圖 保證圈紅的地方 打?qū)?58F678EC-EABC-4320-9FCB...
    ylgwhyh閱讀 1,783評(píng)論 0 1
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)踢京,斷路器誉碴,智...
    卡卡羅2017閱讀 134,599評(píng)論 18 139
  • 心里惶恐,不知所措瓣距,淡定淡定黔帕,一切隨緣 面,1 面對(duì)久了蹈丸,我也就輕車熟路成黄。
    假裝沒(méi)想到閱讀 131評(píng)論 0 1