将子 UIViewConroller 添加到 UITabBarController

Posted

技术标签:

【中文标题】将子 UIViewConroller 添加到 UITabBarController【英文标题】:add child UIViewConroller to UITabBarController 【发布时间】:2018-11-16 12:51:27 【问题描述】:

我的应用程序的结构如下:

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

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

我已尝试将子项添加到 UITabBarController 并且它工作正常,我得到的问题是阴影选项卡项被添加到选项卡栏,这是我不想要的。

我已经尝试将孩子添加到导航控制器,但是当导航回堆栈时会增加其他问题,它会关闭孩子而不是自我并加载相同的控制器。

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

我在这里搜索过任何建议,但没有一个与我的情况一样,所以没有帮助。

谢谢

【问题讨论】:

你想要 UIViewContrller1,2,3... 在孩子可见时调整大小吗? 不,我不需要调整控制器的大小。 【参考方案1】:

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

如果是这种情况,标签栏控制器会将子控制器添加到其viewControllers 数组中。

您可以在添加孩子后立即致电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 是否真的在那个数组中。只是为了更安全。

【讨论】:

我会尝试并告诉你进展如何 好吧,我遇到了同样的问题并尝试了你的解决方案:它正在工作,但我认为不添加视图控制器作为子视图控制器没有区别......我刚刚检查了调试视图层次结构和视图控制器未显示。而且,子视图控制器没有父视图,也没有调用它的生命周期方法。【参考方案2】:

问题:

将子视图控制器添加到UITablViewConltroller 会向标签栏添加一个新标签。这在 ios 13.4 中很明显

解决方案

解决方案是覆盖 viewControllers 并仅返回原始控制器。

/// 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

【讨论】:

【参考方案3】:

最新:

过滤掉 viewControllers 属性实际上不起作用(请参阅下面的“旧答案”),我们在某个时候再次使用该解决方案解决了问题。

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

PD:您可能希望覆盖 UIViewController 的所有 childFor... 方法,以便状态栏样式、主页指示器等与普通 UITabBarController 一样工作。

旧答案:

不幸的是,没有一个提议的解决方案对我有用,但我只是通过从 UITabBarController 的 viewControllers getter 中过滤掉孩子来实现它:

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

【讨论】:

以上是关于将子 UIViewConroller 添加到 UITabBarController的主要内容,如果未能解决你的问题,请参考以下文章

必须使用延迟实例化的UI视图将子视图添加到视图控制器两次

将子视图添加到 NSView 以获得类似国际象棋的网格

如何在将数据加载到 UIViewConroller Swift 时创建正在加载的 UIView

将子视图添加到 UICollectionViewCell 子类?

将子视图添加到 NSView

将子组件添加到父组件并将父组件添加到文档