如何将现有的UIViewController(由UITabController控制)更改为弹出式显示?

huangapple go评论68阅读模式
英文:

How to change an existing UIViewController (which is controlled by a UITabController) so it will appear as a pop up?

问题

抱歉,无法满足你的请求。

英文:

Apologies, Swift newbie here. I know there are other answers to questions "similar" to this, but I believe this scenario is different:

I am making some UI changes to an existing app. As you can see from the included image, the UI was created from the storyboard. There is a Main Tab Controller that controls 5 UIViewControllers. They all work fine, but I need VC4 to open as a pop up on top of whichever other VC is displayed at the time. I've tried setting different Transition Style and Presentation settings but they don't seem to change anything.

I'd like it to slide up from the bottom. Also (and it's not shown in this example image) there would be a smaller View in the center of VC4 which will be a dialog that would need to be dismissed before anything else (including other Tab Bar items) could happen. Ideally, the area around this smaller view would be a dimmed version of whichever VC is underneath.

How do I accomplish this?

如何将现有的UIViewController(由UITabController控制)更改为弹出式显示?

答案1

得分: 1

以下是翻译的代码部分:

// 创建一个自定义的 UITabBarController 子类
class SpecialTabBarController: UITabBarController {
    private var lastViewController: UIViewController?

    // 当设置视图控制器时,替换最后的视图控制器为虚拟控制器(使选项卡正常显示),
    // 并保存真正的最后的视图控制器以便需要时以模态方式呈现。
    override var viewControllers: [UIViewController]? {
        didSet {
            if let viewControllers, viewControllers.count > 1 {
                lastViewController = viewControllers.last
                var newVCs = Array(viewControllers.dropLast())
                let extra = UIViewController()
                extra.tabBarItem = lastViewController?.tabBarItem
                newVCs.append(extra)
                super.viewControllers = newVCs
            }
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        delegate = self

        if let vcs = viewControllers {
            viewControllers = vcs
        }
    }
}

// 扩展 SpecialTabBarController 以实现 UITabBarControllerDelegate
extension SpecialTabBarController: UITabBarControllerDelegate {
    // 当点击选项卡时,确认是否应显示相应的控制器。
    // 在这里,我们禁用显示最后的视图控制器,然后手动呈现它。
    func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
        if let lastViewController, viewController === viewControllers?.last {
            present(lastViewController, animated: true)
            return false
        } else {
            return true
        }
    }
}

这个解决方案适用于以编程方式创建的选项卡栏控制器以及在故事板中创建的选项卡栏控制器。要在故事板中使用,将选项卡栏控制器的类从默认的 UITabBarController 更改为 SpecialTabBarController 即可。

请注意,这个解决方案有一个限制,即 SpecialTabBarController 将自己设置为自己的 UITabBarControllerDelegate,因此无法将任何其他对象设置为委托。不过,如果需要,可以有解决方法,留给读者自行处理。

至于在最后的视图控制器(VC4)中心显示对话框的部分,您可以使该视图控制器的代码在其出现时显示一个 UIAlertController

英文:

The following solution involves creating a custom UITabBarController subclass. This custom class saves off the controller's last view controller and replaces it with an empty view controller. Then it intercepts a check if a tab should be selected. If the last tab is being selected then the selection is rejected and then the last view controller is presented modally.

class SpecialTabBarController: UITabBarController {
    private var lastViewController: UIViewController?

    // When the view controllers are set, replace the last view controller
    // with a dummy controller (so the tab appears normally). Save off the
    // the real last view controller for modal presentation when needed.
    override var viewControllers: [UIViewController]? {
        didSet {
            if let viewControllers, viewControllers.count > 1 {
                lastViewController = viewControllers.last
                var newVCs = Array(viewControllers.dropLast())
                let extra = UIViewController()
                extra.tabBarItem = lastViewController?.tabBarItem
                newVCs.append(extra)
                super.viewControllers = newVCs
            }
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        delegate = self

        if let vcs = viewControllers {
            viewControllers = vcs
        }
    }
}

extension SpecialTabBarController: UITabBarControllerDelegate {
    // When a tab is tapped, this is called to confirm whether the
    // corresponding controller should be shown. Here we disable the
    // showing of the last view controller and then manually present it.
    func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
        if let lastViewController, viewController === viewControllers?.last {
            present(lastViewController, animated: true)
            return false
        } else {
            return true
        }
    }
}

This solution will work with a programmatically created tab bar controller as well as with one created in a storyboard. To work in a storyboard, update the tab bar controller's class from the default of UITabBarController to SpecialTabBarController. That's the only change to make this work.

This solution does cause one limitation. Since SpecialTabBarController makes itself its own UITabBarControllerDelegate, you can't make any other object the delegate. Though there are solutions to this if needed. That's left as an exercise for the reader.

For the dialog you want in the center of the last view controller (VC4), you can have the code for that view controller display a UIAlertController when it appears.

huangapple
  • 本文由 发表于 2023年4月17日 13:00:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76031841.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定