iOS如何用代碼控制以不同屏幕方向打開新頁面?

来源:http://www.cnblogs.com/8hao/archive/2016/03/08/5253803.html
-Advertisement-
Play Games

代碼示例:https://github.com/johnlui/Swift-On-iOS/tree/master/ControlOrientation/ControlOrientation 環境要求:Xcode 7 / Swift2.0 前兩天遇到了一個 “使用指定的不同屏幕方向打開新頁面” 的需求


代碼示例:https://github.com/johnlui/Swift-On-iOS/tree/master/ControlOrientation/ControlOrientation

環境要求:Xcode 7 / Swift2.0

前兩天遇到了一個 “使用指定的不同屏幕方向打開新頁面” 的需求,需求很簡單:APP 一直保持豎屏,要求新打開的頁面能夠指定為橫屏或豎屏,並且不允許自動切換,新頁面退出後要恢復豎屏。

準備工作

新建一個單頁面項目,命名為 ControlOrientation。接下來取消 Landscape Right 的勾選,我們的 APP 將只支持 豎屏(Portrait)和 Landscape Left:

Image

以橫屏打開新頁面

給 Main.storyboard 拖入一個 View Controller,新建一個繼承自 UIViewController 的類,名為 SecondViewController,然後將兩者綁定。之後給新建的這個 View Controller 賦予 StoryBoard ID 值 “secondVC”:

簡單 Google 便可以得到代碼方式指定橫屏打來新頁面的方式:

在新頁面的 viewDidLoad 中執行:

UIDevice.currentDevice().setValue(UIInterfaceOrientation.LandscapeLeft.rawValue, forKey: "orientation")

在啟動頁中間添加一個居中的按鈕,拖動綁定點擊事件,加入載入新頁面的代碼:

Image

@IBAction func openNewVC(sender: AnyObject) {
    if let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("secondVC") as? SecondViewController {
        self.presentViewController(vc, animated: true, completion: nil)
    }
}

運行!查看效果:

Image

代碼控制橫屏成功!

還有一個收尾工作:給 SecondViewController 增加一個退出按鈕,這一步就不再描述啦。然後再次運行項目,查看效果:

Image

出來之後也變橫屏了哎,這不是我們想要的。

屏幕方向鎖定

重讀文章開頭的需求,我們就會發現需求要求我們在任何一個界面都不能因為手機物理方向的變化而自動改變屏幕方向,稍微 Google 一下,我們就會得到鎖死屏幕方向的代碼:

給 ViewController 和 SecondViewController 都增加一個函數:

override func shouldAutorotate() -> Bool {
    return false
}

為了直觀的給大家展示,我們將通過手動改變模擬器的方向來模擬真機屏幕方向的變化(改變模擬器屏幕方向的快捷鍵是 Command 加左或者右),檢驗效果:

Image

簡直完美呀!是不是覺得有點太簡單了?這麼容易就實現了?當然不是,這麼容易我還寫個毛的文章呀。

神級 BUG

既然新打開橫屏已經完美解決了,那麼新打開豎屏怎麼樣呢?讓我們把那一行切換屏幕方向的代碼註釋掉,運行查看結果:

Image

BUG 了!!

解決 BUG

這個 bug 我搞了兩天,雖然不是一直在搞它,但是總時長也至少有八個小時。其實嚴格意義上來講,這並不是 bug,這隻是我們不知道怎麼才能搞定而已。最後我終於搞明白了這個 BUG 背後的運行原理,先說解決方案:

豎屏解決方案

在第一個頁面 ViewController 中增加以下兩個函數:

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.Portrait
}
override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
    return UIInterfaceOrientation.Portrait
}

在第二個頁面 SecondViewController 中增加兩個函數:

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.Portrait
}
override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
    return UIInterfaceOrientation.Portrait
}

查看效果:

Image

豎屏搞定!

橫屏解決方案

將 SecondViewController 中的函數改為:

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.All
}
override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
    return UIInterfaceOrientation.LandscapeLeft
}

別忘了打開 viewDidLoad 函數中的橫屏控制代碼哦。查看效果:

Image

橫屏搞定!

全搞定了嗎?並沒有

我們還是 Too Young Too Simple,在我們簡陋的例子中,似乎確實已經全搞定了,但是實際工程中大多數項目都不是普通 View Controller 作為根控制器哦~

我們測試一下 QQ、微信、微博 等 APP 採用的通用方案:根控制器為 TabBarController,之後嵌套 NavigationController,然後放入 ViewController 頁面進行展示,然後 present 出 SecondViewController。

搭 VIE TNV(TabbarController->NavigationController->ViewController) 架構

我們可不是跟風在國外上市的中國互聯網公司拆 VIE 架構哦~

  • 選中 ViewController,點擊菜單中的 Editor -> Embed In -> Navigation Controller,第一層嵌套完成。

     

     

  • 選中 NavigationController,點擊菜單中的 Editor -> Embed In -> Tab Bar Controller,第二層嵌套完成。

如圖:

Image

查看效果:

Image

這他媽什麼玩意兒 o(╯□╰)o

終極解決方案

我埋坑的過程就不細說了,下麵直接給出特性分析及解決方案:

特性分析

跟 shouldAutorotate() 不同,判斷是否應該改變 APP 屏幕方向並不會檢測當前顯示的 View Controller 的屬性,而是去檢測根 View Controller 的屬性,所以我們要從 TabBarController 一路獲取到當前 View Controller。

解決方案

新建一個繼承於 UITabBarController 的類,名為 TabBarController,將其和 StoryBoard 中的 Tab Bar Controller 頁面綁定。該類完整代碼如下:

import UIKit

class TabBarController: UITabBarController, UITabBarControllerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.delegate = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    override func shouldAutorotate() -> Bool {
        return false
    }
    func tabBarControllerSupportedInterfaceOrientations(tabBarController: UITabBarController) -> UIInterfaceOrientationMask {
        return self.selectedViewController!.supportedInterfaceOrientations()
    }
    func tabBarControllerPreferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
        return self.selectedViewController!.preferredInterfaceOrientationForPresentation()
    }
}

同樣,新建一個繼承於 UINavigationController 的類,名為 NavigationController,將其和 StoryBoard 中的 Navigation Controller 頁面綁定。向該類添加以下代碼:

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return self.visibleViewController!.supportedInterfaceOrientations()
}
override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
    return self.visibleViewController!.preferredInterfaceOrientationForPresentation()
}

檢查結果

Image

寫在最後

通過本文我們可以總結出以下兩點:

  • 是否自動轉換屏幕方向由當前顯示的 View Controller 決定。

  • 是否支持橫屏和是否優先選擇橫屏由 rootViewController 決定,若有多層結構嵌套,則需要層層專遞,將控制權交給當前顯示的頁面。類似於 代理傳值 和 延遲靜態綁定。

另外,我利用 Swift 的 enum 給 SecondViewController 類加上了一個優雅的 橫屏/豎屏 控制開關,具體代碼可以在 Github 上查看。

 

 

問啊-定製化IT教育平臺,牛人一對一服務,有問必答,開發編程社交頭條 官方網站:www.wenaaa.com 下載問啊APP,參與官方懸賞,賺百元現金。

QQ群290551701 聚集很多互聯網精英,技術總監,架構師,項目經理!開源技術研究,歡迎業內人士,大牛及新手有志於從事IT行業人員進入!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 作者: "@gzdaijie" 本文為作者原創,轉載請註明出處:http://www.cnblogs.com/gzdaijie/p/5255084.html 目錄 1.Activity生命周期 1.1 Activity生命周期簡介與測試 1.2 設備旋轉時的生命周期與數據恢復 1.3 Activit
  • EventBus是一個Android上用的消息分發的類庫,非常靈活好用,主要的原理是利用了反射註冊以及調用. 本文是在閱讀EventBus的源碼過程中所記錄的東西, 遇到不懂的去查了,然後留下了鏈接. 有點流水賬,講得也不是很深入,如果有錯請幫忙指正.
  • 當Activity 處於Android 應用中運行時,它的活動狀態由 Android 以 Activity 棧的形式管理。當前活動的Activity位於棧頂。隨著不同應用的運行,每個Activity都有可能從活動狀態轉入非活動狀態,也可能從非活動狀態轉入活動狀態。 Activity 的生命周期 歸納
  • 所謂的單例就是:一個應用程式(app)只有一個實例化對象,這個對象就是單例,一般用於音樂播放器和工具類 在這裡教大家如何手動創建單例,一種是利用互斥鎖的方式,另一種是利用dispatch的一次性執行. 1//通過互斥鎖創建單例 2 +(instancetype)sharedNetWorkTools
  • 概述 我們平時也使用了很多的xcode插件,雖然官方對於插件製作沒有提供任何支持,但是載入三方的插件,預設還是被允許的.第三方的插件,需要存放在 ~/Library/Application Support/Developer/Shared/Xcode/Plug-ins文件夾中,尾碼名必須是.xcpl
  • 用eclipse新建Android工程時,自動生成的appcompat_v7出錯,有個紅色交叉,而且新建的Android工程有一個紅色感嘆號。 這時你去看看你新建的Android工程是不是沒有生成R文件。當你Refresh和Clean都毫無成效後,不妨更新sdk試試。 更新sdk的時候只需要安裝SD
  • Android的UI線程主要負責處理用戶的按鍵事件、用戶觸屏事件及屏幕繪圖事件等,因此開發者的其他操作不應該、也不能阻塞UI線程,否則UI界面將會變得停止響應——用戶感覺非常糟糕。(總之,開發者需要牢記:不要再UI線程中執行一些耗時的操作)。 為了避免UI線程失去響應的問題,Android建議將耗時
  • 在iOS系統,使用Url Scheme框架在APP間互相跳轉和傳遞數據,本文只介紹如果檢測和跳轉。 Url Scheme框架 如果你想知道ios設備中是否安裝QQ這個軟體,我們可以通過一個簡單方法判斷到 if ([[UIApplication sharedApplication] canOpenUR
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...