【问题标题】:Swap rootViewController with animation?用动画交换 rootViewController?
【发布时间】:2017-04-29 21:31:15
【问题描述】:

我正在尝试使用标签栏切换到另一个根视图控制器;通过应用程序委托,我想添加过渡动画。默认情况下,它只会显示没有任何动画的视图。

let tabBar = self.instantiateViewController(storyBoard: "Main", viewControllerID: "MainTabbar")
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window = UIWindow(frame: UIScreen.main.bounds)
appDelegate.window?.rootViewController = tabBar
appDelegate.window?.makeKeyAndVisible()

这就是我切换到另一个 rootview 控制器的方式。

【问题讨论】:

    标签: swift xcode swift3 uiviewanimation rootview


    【解决方案1】:

    试试这个:

    UIView.transition(from: appdelegate.window.rootViewController!.view, to: tabbar.view, duration: 0.6, options: [.transitionCrossDissolve], completion: {
        _ in
        appdelegate.window.rootViewController = tabbar
    })
    

    【讨论】:

    • 这实际上工作得很好。虽然我希望提供的动画类型有更多种类。
    • 简单又好用!
    【解决方案2】:

    您可以使用UIView.transition(with: view) 替换rootViewControllerUIWindow

    guard let window = UIApplication.shared.keyWindow else {
        return
    }
    
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let vc = storyboard.instantiateViewController(withIdentifier: "MainTabbar")
    
    // Set the new rootViewController of the window.
    // Calling "UIView.transition" below will animate the swap.
    window.rootViewController = vc
    
    // A mask of options indicating how you want to perform the animations.
    let options: UIView.AnimationOptions = .transitionCrossDissolve
    
    // The duration of the transition animation, measured in seconds.
    let duration: TimeInterval = 0.3
    
    // Creates a transition animation.
    // Though `animations` is optional, the documentation tells us that it must not be nil. ¯\_(ツ)_/¯
    UIView.transition(with: window, duration: duration, options: options, animations: {}, completion:
    { completed in
        // maybe do something on completion here
    })
    

    【讨论】:

    • 做得很好(Y)。
    • 谢谢你的帮助
    • 我得到了一个轻微的动画故障。 rootViewController.view.frame 不包括我的状态栏框架。必须手动调整框架以考虑状态栏占据前 20 个像素。
    • 只是指出:选项参数在这里什么都不做。
    • 由于动画块是空的,这是如何工作的?它正在工作我只是对如何......感到困惑
    【解决方案3】:

    我正在尝试切换到另一个根视图控制器...我想添加过渡动画

    我有一个应用程序可以做到这一点:它用动画改变根视图控制器(它叫做 Albumen)。

    但我的应用实际上并没有真正改变根视图控制器。根视图控制器是一个永远不会改变的自定义容器视图控制器。它的视图从未见过,也没有任何功能。它唯一的工作就是成为发生变化的地方:它将一个子视图控制器交换为另一个——因此过渡动画起作用了。

    换句话说,您将一个视图控制器添加到视图控制器层次结构中,就在层次结构的顶部,整个问题就得到了巧妙而正确的解决。

    【讨论】:

    • 好主意,我在 SwiftUI 中得到了这个工作,它让我的生活变得更好!
    • 简单有效!谢谢!
    【解决方案4】:

    另一种解决方案:

    let stb = UIStoryboard(name: "YOUR_STORYBOARD_NAME", bundle: nil)
    let rootVC = stb.instantiateViewController(withIdentifier: "YOUR_TABBAR_VIEWCONTROLLER_NAME")
    let snapshot = (UIApplication.shared.keyWindow?.snapshotView(afterScreenUpdates: true))!
    rootVC.view.addSubview(snapshot)
    
    UIApplication.shared.keyWindow?.rootViewController = rootVC
    UIView.transition(with: snapshot, 
                      duration: 0.4,
                      options: .transitionCrossDissolve,
                      animations: { 
                          snapshot.layer.opacity = 0
                      },
                      completion: { status in 
                          snapshot.removeFromSuperview()
                      })
    

    【讨论】:

      【解决方案5】:

      斯威夫特 4

      将函数粘贴到AppDelegate

      func setRootViewController(_ vc: UIViewController, animated: Bool = true) {
          guard animated, let window = self.window else {
              self.window?.rootViewController = vc
              self.window?.makeKeyAndVisible()
              return
          }
      
          window.rootViewController = vc
          window.makeKeyAndVisible()
          UIView.transition(with: window,
                            duration: 0.3,
                            options: .transitionCrossDissolve,
                            animations: nil,
                            completion: nil)
      }
      

      【讨论】:

      • 如果我同时使用 appdelegate 和 scenedelegate 怎么办?
      • 虽然,方法是类型,所以animations 是可选的,实际上,如果您实际传递 nil,则此代码不应该工作。如果你传递一个空的闭包,它确实有效。
      【解决方案6】:

      我根据 d.felber 的回答为此创建了一个辅助类:

      
          import UIKit
      
          class ViewPresenter {
      
              public static func replaceRootView(for viewController: UIViewController,
                                         duration: TimeInterval = 0.3,
                                         options: UIView.AnimationOptions = .transitionCrossDissolve,
                                         completion: ((Bool) -> Void)? = nil) {
                  guard let window = UIApplication.shared.keyWindow else {
                      return
                  }
      
                  guard let rootViewController = window.rootViewController else {
                      return
                  }
      
                  viewController.view.frame = rootViewController.view.frame
                  viewController.view.layoutIfNeeded()
      
                  UIView.transition(with: window, duration: duration, options: options, animations: {
                      window.rootViewController = viewController
                  }, completion: completion)
              }
          }
      

      你可以这样使用它:

          let loginVC = SignInViewController(nibName: "SignInViewController", bundle: nil)
          ViewPresenter.replaceRootView(for: loginVC)
      

      ViewPresenter.replaceRootView(for: loginVC, duration: 0.3, options: .transitionCrossDissolve) { 
      (bool) in
             // do something
      }
      

      【讨论】:

        【解决方案7】:

        更新 Swift 5.3 版本:

            let foregroundedScenes = UIApplication.shared.connectedScenes.filter { $0.activationState == .foregroundActive }
            let window = foregroundedScenes.map { $0 as? UIWindowScene }.compactMap { $0 }.first?.windows.filter { $0.isKeyWindow }.first
            
            guard let uWindow = window else { return }
        
            uWindow.rootViewController = customTabBarController
            UIView.transition(with: uWindow, duration: 0.3, options: [.transitionCrossDissolve], animations: {}, completion: nil)
        }
        

        【讨论】:

          猜你喜欢
          • 2012-02-08
          • 2011-12-03
          • 1970-01-01
          • 1970-01-01
          • 2011-03-11
          • 1970-01-01
          • 2011-12-24
          • 2012-04-08
          相关资源
          最近更新 更多