【问题标题】:iOS - stack fullscreen viewController when presenting another viewControlleriOS - 在呈现另一个视图控制器时堆栈全屏视图控制器
【发布时间】:2020-02-24 19:13:49
【问题描述】:

我有一个带有两个标签的UITabBarViewController。我想在其中一个选项卡中全屏显示 viewController。我使用了以下代码。

    let navCtrl = UINavigationController(rootViewController: eventViewController)
    navCtrl.modalPresentationStyle = .fullScreen        
    self.navigationController?.present(navCtrl, animated: true)

它有效。 EventViewController 是全屏的。但是,当在EventViewController 中呈现另一个viewController 时,EventViewController 仍然是全屏的。但我希望它像往常一样缩小尺寸和堆叠(如图所示)。为此,我将modalPresentationStyle 更改为overCurrentContext

    let navCtrl = UINavigationController(rootViewController: eventViewController)
    navCtrl.modalPresentationStyle = .overCurrentContext        
    self.navigationController?.present(navCtrl, animated: true)

这样做,但它会导致另一个问题:如果我更改选项卡并关闭 EventViewController,则呈现的 viewController 是 black,如 question 中所述(没有一个答案有帮助) em>。


基本上我希望EventController 是全屏的,但在其中显示另一个控制器时会缩小尺寸。怎么做?

更新

一个具有相同问题的简单项目。

class TabBarController: UITabBarController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let ctrl = TabZeroViewController()
        ctrl.tabBarItem.image = UIImage(named: "archived-task")
        ctrl.tabBarItem.title = "One"


        let test = TabOneViewController()
        test.tabBarItem.image = UIImage(named: "Test")
        test.tabBarItem.title = "Test"

        let tabBarList = [ctrl, test ]

        self.viewControllers = tabBarList.map {
            let nav = UINavigationController(rootViewController: $0)
            nav.interactivePopGestureRecognizer?.isEnabled = true
            return nav
        }
    }
}



class TabZeroViewController: UITableViewController {


    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.delegate = self
        self.tableView.dataSource = self

        self.view.backgroundColor = .white
    }

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell =  UITableViewCell()
        cell.textLabel?.text = "\(indexPath.row)"
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let ctrl = ModalTableViewController()

        let nav = UINavigationController(rootViewController: ctrl)
        nav.modalPresentationStyle = .fullScreen

        self.navigationController?.present(nav, animated: true)
    }

}

class ModalTableViewController: UITableViewController {
    override func viewDidLoad() {
        self.view.backgroundColor = .red
        let button = UIButton()
        button.setTitle("Cancel", for: .normal)
        button.addTarget(self, action: #selector(dismissModal), for: .allEvents)
        let item = UIBarButtonItem()
        item.customView = button
        self.navigationItem.leftBarButtonItem = item
        self.tableView.dataSource = self
        self.tableView.delegate = self
    }

    @objc func dismissModal() {
        self.dismiss(animated: true, completion: nil)
    }


    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell =  UITableViewCell()
        cell.textLabel?.text = "Event"
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let ctrl = EventViewController()
        let nav = UINavigationController(rootViewController: ctrl)
         nav.modalPresentationStyle = .overCurrentContext
        self.navigationController?.present(nav, animated: true)
    }
}


class TabOneViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

    }
}




class EventViewController: UITableViewController {

    override func viewDidLoad() {
        self.view.backgroundColor = .red
        let button = UIButton()
        button.setTitle("Cancel", for: .normal)
        button.addTarget(self, action: #selector(dismissModal), for: .allEvents)
        let item = UIBarButtonItem()
        item.customView = button
        self.navigationItem.leftBarButtonItem = item
        self.tableView.dataSource = self
        self.tableView.delegate = self
    }

    @objc func dismissModal() {
        self.dismiss(animated: true, completion: nil)
    }


    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell =  UITableViewCell()
        cell.textLabel?.text = "Event"
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let ctrl = EventViewController()
        let nav = UINavigationController(rootViewController: ctrl)
        self.navigationController?.present(nav, animated: true)
    }
}

将此代码添加到willConnectTo 中的SceneDelegate

 if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = TabBarController()
        self.window = window
        window.makeKeyAndVisible()
    }

当您在第一个选项卡上时,选择一个表格单元格以打开 ModalTableViewController。然后更改标签并关闭ModalTableViewController

【问题讨论】:

  • 首先,您需要更新导航控制器中的视图控制器,但导航控制器旨在用于推送视图控制器。因为它可能会导致意外行为。
  • 我已经运行了相同的流程并且它按预期工作。有一件事要问:以 EventViewController 为根的导航控制器没有显示在整个屏幕上,您如何在显示时更改选项卡。请向我澄清这一点。
  • 您确实提供了一个导航控制器,当您关闭任何不会关闭附加的导航控制器的控制器时,这就是您面临黑屏问题的原因。
  • @neerajjoshi,按照以下步骤操作,1. 设置 modalPresentationStyle = .overCurrentContext 2. 呈现 viewCtrl 3. 选择另一个选项卡,然后选择相同的选项卡。 4 关闭呈现的viewCtrl。
  • @mahan ,我可以玩一下你的源代码吗?如果是,那么您可以创建具有此类场景的示例项目并上传到 GitHub。

标签: ios swift uiviewcontroller


【解决方案1】:

例如项目 - 在全屏上显示视图会隐藏 TabBar。但是我稍微更改了代码以提出可行的解决方案。可能你会想稍微改变一下,但我希望这能把你推向好的方向:)

实际上需要关闭ModalTableViewController以避免黑屏。

class TabBarController: UITabBarController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let ctrl = TabZeroViewController()
        ctrl.tabBarItem.image = UIImage(named: "archived-task")
        ctrl.tabBarItem.title = "One"


        let test = TabOneViewController()
        test.tabBarItem.image = UIImage(named: "Test")
        test.tabBarItem.title = "Test"

        let tabBarList = [ctrl, test ]

        let viewControllers: [UIViewController] = tabBarList.map {
            let nav = UINavigationController(rootViewController: $0)
            nav.interactivePopGestureRecognizer?.isEnabled = true
            nav.tabBarItem = $0.tabBarItem
            return nav
        }

        self.setViewControllers(viewControllers, animated: false)
    }

    override var selectedViewController: UIViewController? {
        get {return super.selectedViewController}
        set {
            if super.selectedViewController?.presentedViewController != nil {
                super.selectedViewController?.dismiss(animated: false, completion: nil)
            }
            super.selectedViewController = newValue
        }
    }
}



class TabZeroViewController: UITableViewController {


    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.delegate = self
        self.tableView.dataSource = self

        self.view.backgroundColor = .white
    }

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell =  UITableViewCell()
        cell.textLabel?.text = "\(indexPath.row)"
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let ctrl = ModalTableViewController()

        let nav = UINavigationController(rootViewController: ctrl)
        nav.modalPresentationStyle = .currentContext

        self.present(nav, animated: true)
    }

}

class ModalTableViewController: UITableViewController {
    override func viewDidLoad() {
        self.view.backgroundColor = .red
        let button = UIButton()
        button.setTitle("Cancel", for: .normal)
        button.addTarget(self, action: #selector(dismissModal), for: .allEvents)
        let item = UIBarButtonItem()
        item.customView = button
        self.navigationItem.leftBarButtonItem = item
        self.tableView.dataSource = self
        self.tableView.delegate = self
    }

    @objc func dismissModal() {
        self.presentingViewController?.dismiss(animated: false, completion: nil)
    }


    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell =  UITableViewCell()
        cell.textLabel?.text = "Event"
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let ctrl = EventViewController()
        let nav = UINavigationController(rootViewController: ctrl)
         nav.modalPresentationStyle = .fullScreen
        self.navigationController?.present(nav, animated: true)
    }
}


class TabOneViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
    }
}




class EventViewController: UITableViewController {

    override func viewDidLoad() {
        self.view.backgroundColor = .red
        let button = UIButton()
        button.setTitle("Cancel", for: .normal)
        button.addTarget(self, action: #selector(dismissModal), for: .allEvents)
        let item = UIBarButtonItem()
        item.customView = button
        self.navigationItem.leftBarButtonItem = item
        self.tableView.dataSource = self
        self.tableView.delegate = self
    }

    @objc func dismissModal() {
        self.dismiss(animated: true, completion: nil)
    }


    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell =  UITableViewCell()
        cell.textLabel?.text = "Event"
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let ctrl = EventViewController()
        let nav = UINavigationController(rootViewController: ctrl)
        self.navigationController?.present(nav, animated: true)
    }
}

祝你好运!

【讨论】:

    【解决方案2】:

    试试这个代码以模态方式呈现屏幕:

     func getImageFromView() -> UIImage {
    
            let layer = UIApplication.shared.keyWindow?.layer
            let scale = UIScreen.main.scale
            UIGraphicsBeginImageContextWithOptions(layer?.frame.size ?? CGSize.zero, false, scale)
            if let context = UIGraphicsGetCurrentContext() {
                layer?.render(in: context)
                let image = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
                return image ?? UIImage()
            }
            return UIImage()
        }
    
    
    /// This is the method to present  screen modally
    /// - parameter controller: controller instance on which screen will be presented
    func presentScreenModally(controller: UIViewController, animated: Bool) {
        let loginController  = UIStoryboard.loadLoginViewController()//Get instance of controller form storyboard
        loginController.bgTranParentImg = getImageFromView()
    
        let bgImage = getImageFromView()
        let presentationStyleViewController = UIStoryboard.loadPresentationStyleController()// This is another controller, which I am pasting below
        presentationStyleViewController.bgimage = bgImage
        presentationStyleViewController.loginController = loginController
        presentationStyleViewController.addChild(loginController)
        controller.view.window?.addSubview(presentationStyleViewController.view)
        loginController.view.frame = presentationStyleViewController.containerView.bounds
        presentationStyleViewController.containerView.addSubview(loginController.view)
    
        let navigationController = UINavigationController(rootViewController: presentationStyleViewController)
        navigationController.navigationBar.isHidden = true
        navigationController.modalPresentationStyle = .fullScreen
        controller.navigationController?.present(navigationController, animated: animated, completion: nil)
    }
    

    PresentationStyleViewController 类:

    class PresentationStyleViewController: UIViewController {
    
        @IBOutlet var containerView: UIView!
        @IBOutlet var containeTopConstraint: NSLayoutConstraint!
        @IBOutlet var containerBottomConstraint: NSLayoutConstraint!
        @IBOutlet var backgroundImage: UIImageView!
    
        var bgimage: UIImage?
        let topPadding: CGFloat = 30
        var loginController: LoginViewController?
    
        override func viewDidLoad() {
            super.viewDidLoad()
            self.uiSetup()
        }
    
        override func viewDidAppear(_ animated: Bool) {
            restorePopup()
        }
    
        /// Initial UI setup
        func uiSetup() {
            containeTopConstraint.constant = self.view.frame.size.height
            backgroundImage.image = bgimage
        }
    
        @IBAction func panGesture(_ sender: UIPanGestureRecognizer) {
            guard let piece = sender.view else {return}
            let translation = sender.translation(in: piece.superview)
            containeTopConstraint.constant = translation.y >= topPadding ? translation.y : topPadding
    
            if sender.state == .ended || sender.state == .cancelled {
                if containeTopConstraint.constant > self.view.frame.size.height/4 && translation.y > 0 {
                    self.dismissPopup()
                } else {
                    self.restorePopup()
                }
            }
        }
    
        /// Dismisses popup and controller
        func dismissPopup() {
            containeTopConstraint.constant = self.view.frame.size.height
            UIView.animate(withDuration: 0.3,
                           animations: {
                            self.view.layoutIfNeeded()
            }, completion: { (_) in
                self.loginController?.btnClick_cross(UIButton())
                self.dismiss(animated: false)
            })
        }
    
        /// Restores popup at initial position
        func restorePopup() {
            containeTopConstraint.constant = topPadding
            UIView.animate(withDuration: 0.3,
                           animations: {
                            self.view.layoutIfNeeded()
            }, completion: nil)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-08
      • 1970-01-01
      • 2017-02-03
      • 2016-11-20
      • 2016-06-18
      • 2014-12-12
      • 1970-01-01
      相关资源
      最近更新 更多