添加 child UIViewConroller 到 UITabBarController

add child UIViewConroller to UITabBarController

我的应用程序结构如下:

UITabBarController -> UINavigationController -> [UIViewController1, UIViewController2, UIViewController3]

我需要实现的是在一个小框架中的 tabBar 正上方显示和隐藏一个 child UIViewController,因此它在导航堆栈中的所有控制器上都是可见的。因此,当用户在堆栈中来回导航时,如果添加 child,它必须在所有控制器上可见。

我已经尝试将 child 添加到 UITabBarController 并且它工作正常,我遇到的问题是阴影标签栏项目被添加到标签栏,这是我不想要的。

我曾尝试将 child 添加到导航控制器,但这会在返回堆栈时增加其他问题,它会关闭 child 而不是自身并加载相同的控制器。

有没有人对如何在整个导航过程中保留这个 child 控制器有什么建议。

我在这里搜索了任何建议,但是 none 就像我的情况一样,所以没有帮助。

谢谢

我假设您以编程方式将容器视图添加到标签栏控制器中,然后将 child 视图控制器添加到该容器视图中。我说得对吗?

如果是这种情况,tabbar 控制器将 child 控制器添加到其 viewControllers 数组中。

您可以在添加 child 后立即调用 viewControllers?.removeLast() 来解决此问题。

这段代码对我有用:

override func viewDidLoad() {
    super.viewDidLoad()

    let containerView = UIView()
    view.addSubview(containerView)

    containerView.translatesAutoresizingMaskIntoConstraints = false
    containerView.bottomAnchor.constraint(equalTo: tabBar.topAnchor).isActive = true
    containerView.leftAnchor.constraint(equalTo: tabBar.leftAnchor, constant: 40).isActive = true
    containerView.rightAnchor.constraint(equalTo: tabBar.rightAnchor, constant: -40).isActive = true
    containerView.heightAnchor.constraint(equalToConstant: 150).isActive = true

    if let childVC = self.storyboard?.instantiateViewController(withIdentifier: "ChildViewController") {
        addChild(childVC)
        containerView.addSubview(childVC.view)
        childVC.didMove(toParent: self)

        childVC.view.translatesAutoresizingMaskIntoConstraints = false
        childVC.view.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true
        childVC.view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true
        childVC.view.rightAnchor.constraint(equalTo: containerView.rightAnchor).isActive = true
        childVC.view.leftAnchor.constraint(equalTo: containerView.leftAnchor).isActive = true

        if let childIndex = viewControllers?.firstIndex(of: childVC) {
            viewControllers?.remove(at: childIndex)
        }
    }
}

在这里,我不仅调用了 removeLast(),还检查了 childVC 是否确实在该数组中。只是为了安全起见。

问题:

将子视图控制器添加到 UITablViewConltroller 会在选项卡栏中添加一个新选项卡。这清楚地出现在 iOS 13.4

解决方案

解决方案仅覆盖 viewControllers 和 return 原始控制器。

/// Neglect child insertion to `viewControllers`

var _viewControllers: [UIViewController]?

override var viewControllers: [UIViewController]? {
    get {
        return _viewControllers
    }
    set {
        _viewControllers = newValue
    }
}

还有更多

更改标签栏项目徽章

//This would not work any more
//viewControllers?.last?.tabBarItem.badgeValue = badgeValue

//Use this way instead
tabBar.items?.last?.badgeValue = badgeValue

最新:

过滤掉 viewControllers 属性 实际上没有用(见下面的“旧答案”),我们在某个时候用那个解决方案再次遇到了问题。

然后我们所做的是将 UITabBarController 嵌入到 UIViewController 中,然后将我们想要的视图添加到视图控制器中。布局设置为向嵌入式标签栏控制器的标签栏添加约束。它现在似乎可以正常工作了。

PD:您可能想要重写 UIViewController 的所有 childFor... 方法,以便状态栏样式、主页指示器等像使用普通 UITabBarController 一样工作。

旧答案:

不幸的是,提议的解决方案中的

None 对我有用,但我只是通过从 UITabBarController 的 viewControllers getter:[=18 中过滤掉 child 来实现它=]

override var viewControllers: [UIViewController]? {
    get {
        super.viewControllers?.filter { viewController in
            viewController != self.yourChildViewController
        }
    }
    set {
        super.viewControllers = newValue
    }
}