添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
2,836

我们知道,苹果在2019年WWDC要求,2020.4月开始上架的 APP 都强制要求使用 LaunchScreen.storyboard,删除该 storyboard ,改为各种自定义的广告启动页时代已经过去了,那么,对于各大电商来说,每年有各种大、中、小促(越来越频繁,是个节日就促销),因此,活动广告页仍旧必不可少。启动页不能删除,同时还需要广告页,那我们该如何去做呢?

本篇,你将学到如下知识点:

  • 简单了解 LaunchScreen;
  • 制作启动页 + XIB 中设置约束;
  • 双 UIWindow / 单 UIWindow 切换;
  • 二、简单了解 LaunchScreen

    LaunchScreen 很简单,网上有大把的适配方案。你不能动态去设置该 storyboard ,只能提前在 Xcode 中设置。因为要考虑到不同机型分辨率的适配问题,因此,不建议使用一整张图 + 约束,除非你添加一整套不同分辨率的图到工程中,但这样的话,你的整个 app 包就大了。

    个人建议:

  • 背景为纯色填充;
  • 放置小图 + 约束;
  • 放置文字 + 约束;
  • 出于 Demo 好看,我设置了一整张图片 + 两行文字:

  • 图片采用『Aspect Fill』按比例来充满整屏(会被截取),所以为何我会建议用纯背景色了吧,当然,不怕被截的话,那就可以用图片没有问题;
  • 不同颜色的文字设置,如下图:
  • 如何在 XIB 中添加约束?

    拖线的时候,要先按住『 control 』键才行!

    三、UIWindow 与 广告页

    在 AppDelegate 中,我们已经有了一个 window,它的 rootViewController 已经设置为我们的 MainTabBarController,那我们如何先启动我们的广告页,然后再进入我们真正的 TabBarController 呢?

    通常,我们有两种办法:

  • 单 window,rootViewController 先设置广告页VC,之后再换成 TabBarController;
  • 双 window,rootViewController 分别设置广告页VC 和 TabBarController,只不过,广告页 window 在最上面,然后再切换到 TabBarController 的 window;
  • 无论哪种方式,最终的效果都一样,如下图:

    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 时,结束 timer,并进行两个 rootViewController 的切换
                    if self!.seconds <= 0 {
                        self!.terminer()
                    self!.seconds -= 1
            timer.resume()
        func terminer() {
            timer.cancel()
    

    3.2、单 window 替换法

    单 window 替换法如我之前所说,用户点击或者倒计时结束时,将 window.rootViewController = MainTabBarController() 即可,当然,还要加点过渡动画,不然就会显示太过生硬,实现代码如下:

    // 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 小节,再开始本小节的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?[下标].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()
            switchWindow() // 修改这里
        // 同样两种方式可以实现:广告页 -> 主页面:
        // 1. 两个 window 来分别控制不同的业务,然后基于过渡动画来切换 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 是否开启动画的状态(默认是开启)
                                // 之所以先禁止,是防止存在其它动画影响了当前动画
                                // ----------------------------------------
                                // 设置了禁止动画后:
                                // 1. 当前所有正在执行动画的没有任何影响
                                // 2. 未执行的将不会执行动画
                                // ----------------------------------------
                                // 因为我们这个回调是动画已经开始,所以,并不会被强制停止,
                                // 最后再恢复 UIView 是否开启动画的状态即可
                                let old = UIView.areAnimationsEnabled
                                UIView.setAnimationsEnabled(false)
                                window.alpha = 0
                                UIView.setAnimationsEnabled(old)
                              }, completion: { _ in
                                // 切换到主 window,即我们的 MainTabBarController
                                UIApplication.shared.windows.first?.makeKeyAndVisible()
    

    无论哪种用法,对于用户来说,都是一样;同样,最终取决于用单 window 还是双 window 都由项目(可扩展性)、研发(技术、时间、能力)等来决定;但总归,多一种方案多一条路。

    本篇虽然是在介绍如何启动广告页,实际则是让大家学习如何去使用多个 window,以及之间的切换过渡动画(正所谓授之以鱼,不如授之以渔)。多个 window 看似场景不多,其实还是有的,比如:视频类APP,非全屏时,页面滚动,视频控件移出到屏幕外不可见时,APP会在当前创建一个悬浮在右下角的一个单独视频窗口,这就用到了多window 技术。

    既然是广告页,一定会有倒计时的控件不断时间递减,倒计时结束后才会进入我们的首页。下一篇,我将介绍本系列的第一个组件:倒计时组件!(本系列会介绍非常多的常用组件的自定义开发)

    欢迎交流,敬请期待,谢谢!