iOS Swift5從0到1系列(八):雙UIWindow + 啟動頁 vs 廣告頁

聲明:文中的圖片雖然是來自掘金的桨踪,也是來自我的掘金號中的圖片老翘,并非抄襲!

一锻离、前言

我們知道铺峭,蘋果在2019年WWDC要求,2020.4月開始上架的 APP 都強制要求使用 LaunchScreen.storyboard汽纠,刪除該 storyboard 卫键,改為各種自定義的廣告啟動頁時代已經(jīng)過去了,那么虱朵,對于各大電商來說莉炉,每年有各種大、中碴犬、小促(越來越頻繁絮宁,是個節(jié)日就促銷),因此服协,活動廣告頁仍舊必不可少绍昂。啟動頁不能刪除,同時還需要廣告頁偿荷,那我們該如何去做呢窘游?

本篇,你將學(xué)到如下知識點:

  1. 簡單了解 LaunchScreen跳纳;
  2. 制作啟動頁 + XIB 中設(shè)置約束张峰;
  3. 雙 UIWindow / 單 UIWindow 切換;

二棒旗、簡單了解 LaunchScreen

LaunchScreen 很簡單,網(wǎng)上有大把的適配方案撩荣。你不能動態(tài)去設(shè)置該 storyboard 铣揉,只能提前在 Xcode 中設(shè)置。因為要考慮到不同機型分辨率的適配問題餐曹,因此逛拱,不建議使用一整張圖 + 約束,除非你添加一整套不同分辨率的圖到工程中台猴,但這樣的話朽合,你的整個 app 包就大了俱两。

個人建議:

  • 背景為純色填充;
  • 放置小圖 + 約束曹步;
  • 放置文字 + 約束宪彩;

出于 Demo 好看,我設(shè)置了一整張圖片 + 兩行文字:

LaunchScreen.png
  • 圖片采用『Aspect Fill』按比例來充滿整屏(會被截冉不椤)尿孔,所以為何我會建議用純背景色了吧,當(dāng)然筹麸,不怕被截的話活合,那就可以用圖片沒有問題;
  • 不同顏色的文字設(shè)置物赶,如下圖:
multi-color-text.png

如何在 XIB 中添加約束白指?

xib-set-constraints.gif

拖線的時候,要先按住『 control 』鍵才行酵紫!

三告嘲、UIWindow 與 廣告頁

在 AppDelegate 中,我們已經(jīng)有了一個 window憨闰,它的 rootViewController 已經(jīng)設(shè)置為我們的 MainTabBarController状蜗,那我們?nèi)绾蜗葐游覀兊膹V告頁,然后再進(jìn)入我們真正的 TabBarController 呢鹉动?

通常轧坎,我們有兩種辦法:

  1. 單 window,rootViewController 先設(shè)置廣告頁VC泽示,之后再換成 TabBarController缸血;
  2. 雙 window,rootViewController 分別設(shè)置廣告頁VC 和 TabBarController械筛,只不過捎泻,廣告頁 window 在最上面,然后再切換到 TabBarController 的 window埋哟;

無論哪種方式笆豁,最終的效果都一樣,如下圖:

switch-from-adv-to-main.gif

3.1赤赊、添加廣告頁 VC

// AdvertiseViewController.swift

class AdvertiseViewController: BaseViewController {
    
    // 延遲初始化 timer
    lazy var timer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.global())
    // 倒計時的時間
    var seconds = 5

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .kRed
        timeCountDown()
    }
    
    func timeCountDown() {
        timer.schedule(deadline: .now(), repeating: .seconds(1))
        timer.setEventHandler(handler: {
            DispatchQueue.main.async { [weak self] in
                
                // 小于等于 0 時闯狱,結(jié)束 timer,并進(jìn)行兩個 rootViewController 的切換
                if self!.seconds <= 0 {
                    self!.terminer()
                }
                self!.seconds -= 1
            }
        })
        timer.resume()
    }
    
    func terminer() {
        timer.cancel()
    }
}
dir-structure.png

3.2抛计、單 window 替換法

單 window 替換法如我之前所說哄孤,用戶點擊或者倒計時結(jié)束時,將 window.rootViewController = MainTabBarController() 即可吹截,當(dāng)然瘦陈,還要加點過渡動畫凝危,不然就會顯示太過生硬,實現(xiàn)代碼如下:

// AdvertiseViewController.swift

class AdvertiseViewController: BaseViewController {
    ......
    
    func terminer() {
        timer.cancel()
        switchRootController()
    }
    
    //
    // 一個 window 的情況:只用切換 rootViewController 就行
    //
    func switchRootController() {
        let window = UIApplication.shared.windows.first!
        
        // 過渡動畫:0.5s 淡出
        UIView.transition(with: window,
                          duration: 0.5,
                          options: .transitionCrossDissolve,
                          animations: {
                            
                            let old = UIView.areAnimationsEnabled
                            UIView.setAnimationsEnabled(false)
                            window.rootViewController = MainTabBarController()
                            UIView.setAnimationsEnabled(old)

                          }, completion: { _ in
                            // Do Nothing
                          })
    }
}

修改 AppDelegation

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        
        window = UIWindow(frame: UIScreen.main.bounds)
        window?.backgroundColor = .white
        window?.rootViewController = AdvertiseViewController() // 修改這里
        window?.makeKeyAndVisible()
        
        return true
    }
}

3.3晨逝、雙 window 切換法

雙 window 顧名思義蛾默,就是有兩個 window,雙 window 不像單 window咏花,是修改 rootViewController趴生,而是通過 api 來控制哪個 window 可見的方式來切換,同樣也需要有過渡動畫昏翰。(先還原代碼至 3.1 小節(jié)苍匆,再開始本小節(jié)的demo )

修改 AppDelegation

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    // 多個 window:
    // 第 1 個用于主app;
    // 第 2 個用于顯示廣告頁棚菊;
    var windows: [UIWindow]?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        
        // 后一個 window 蓋在前一個之上浸踩,可以通過:
        // windows?[下標(biāo)].makeKeyAndVisible() 來切換顯示
        windows = [
            addWindowWithVC(MainTabBarController()),
            addWindowWithVC(AdvertiseViewController())
        ]
        
        return true
    }

    func addWindowWithVC(_ vc: UIViewController) -> UIWindow {
        let window = UIWindow.init(frame: UIScreen.main.bounds)
        window.backgroundColor = .white
        window.rootViewController = vc
        window.makeKeyAndVisible()
        return window
    }
}

修改 AdvertiseViewController

class AdvertiseViewController: BaseViewController {
    ......
    
    func terminer() {
        timer.cancel()
//        switchRootController()
        switchWindow() // 修改這里
    }
    
    // 同樣兩種方式可以實現(xiàn):廣告頁 -> 主頁面:
    // 1. 兩個 window 來分別控制不同的業(yè)務(wù),然后基于過渡動畫來切換 window统求;
    // 2. 一個 window检碗,兩個 vc,分別是 主vc 和 廣告vc码邻,通過修改 window.rootViewController 來完成折剃;
    func switchWindow() {
        // 第2個 window(廣告窗口)
        let window = UIApplication.shared.windows.last!
        
        // 過渡動畫:淡出
        UIView.transition(with: window,
                          duration: 0.5,
                          options: .transitionCrossDissolve,
                          animations: {

                            // 臨時保存 UIView 是否開啟動畫的狀態(tài)(默認(rèn)是開啟)
                            // 之所以先禁止,是防止存在其它動畫影響了當(dāng)前動畫
                            // ----------------------------------------
                            // 設(shè)置了禁止動畫后:
                            // 1. 當(dāng)前所有正在執(zhí)行動畫的沒有任何影響
                            // 2. 未執(zhí)行的將不會執(zhí)行動畫
                            // ----------------------------------------
                            //
                            // 因為我們這個回調(diào)是動畫已經(jīng)開始像屋,所以怕犁,并不會被強制停止,
                            // 最后再恢復(fù) UIView 是否開啟動畫的狀態(tài)即可
                            let old = UIView.areAnimationsEnabled
                            UIView.setAnimationsEnabled(false)
                            window.alpha = 0
                            UIView.setAnimationsEnabled(old)

                          }, completion: { _ in
                            // 切換到主 window,即我們的 MainTabBarController
                            UIApplication.shared.windows.first?.makeKeyAndVisible()
                          })
    }

無論哪種用法己莺,對于用戶來說奏甫,都是一樣;同樣凌受,最終取決于用單 window 還是雙 window 都由項目(可擴展性)阵子、研發(fā)(技術(shù)、時間胜蛉、能力)等來決定挠进;但總歸,多一種方案多一條路誊册。

四奈梳、總結(jié)

本篇雖然是在介紹如何啟動廣告頁,實際則是讓大家學(xué)習(xí)如何去使用多個 window解虱,以及之間的切換過渡動畫(正所謂授之以魚,不如授之以漁)漆撞。多個 window 看似場景不多殴泰,其實還是有的于宙,比如:視頻類APP,非全屏?xí)r悍汛,頁面滾動捞魁,視頻控件移出到屏幕外不可見時,APP會在當(dāng)前創(chuàng)建一個懸浮在右下角的一個單獨視頻窗口离咐,這就用到了多window 技術(shù)谱俭。

既然是廣告頁,一定會有倒計時的控件不斷時間遞減宵蛀,倒計時結(jié)束后才會進(jìn)入我們的首頁昆著。下一篇,我將介紹本系列的第一個組件:倒計時組件J跆铡(本系列會介紹非常多的常用組件的自定義開發(fā))

歡迎交流凑懂,敬請期待,謝謝梧宫!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末接谨,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子塘匣,更是在濱河造成了極大的恐慌脓豪,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件忌卤,死亡現(xiàn)場離奇詭異扫夜,居然都是意外死亡,警方通過查閱死者的電腦和手機埠巨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門历谍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人辣垒,你說我怎么就攤上這事望侈。” “怎么了勋桶?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵脱衙,是天一觀的道長。 經(jīng)常有香客問我例驹,道長捐韩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任鹃锈,我火速辦了婚禮荤胁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘屎债。我一直安慰自己仅政,他們只是感情好垢油,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著圆丹,像睡著了一般滩愁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上辫封,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天硝枉,我揣著相機與錄音,去河邊找鬼倦微。 笑死妻味,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的璃诀。 我是一名探鬼主播弧可,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼劣欢!你這毒婦竟也來了棕诵?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤凿将,失蹤者是張志新(化名)和其女友劉穎校套,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體牧抵,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡笛匙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了犀变。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片妹孙。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖获枝,靈堂內(nèi)的尸體忽然破棺而出蠢正,到底是詐尸還是另有隱情,我是刑警寧澤省店,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布嚣崭,位于F島的核電站,受9級特大地震影響懦傍,放射性物質(zhì)發(fā)生泄漏雹舀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一粗俱、第九天 我趴在偏房一處隱蔽的房頂上張望说榆。 院中可真熱鬧,春花似錦、人聲如沸签财。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽荠卷。三九已至,卻和暖如春烛愧,著一層夾襖步出監(jiān)牢的瞬間油宜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工怜姿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留慎冤,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓沧卢,卻偏偏與公主長得像蚁堤,于是被迫代替她去往敵國和親但狭。 傳聞我的和親對象是個殘疾皇子披诗,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

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