swift 在UITabBar顶部查看

m528fe3b  于 2023-01-01  发布在  Swift
关注(0)|答案(7)|浏览(127)

与Spotify或Apple Music应用在播放歌曲时的操作类似,它会在UITabBar顶部放置一个自定义视图:

我尝试过的解决方案:

1.具有最大容器视图的ViewController中的UITabBarController,以及底部布局参考线上方容器视图顶部49 pt的自定义视图:

**问题:**嵌入在UITabBarController中的ViewControllers中约束到底部的任何内容都不会显示,因为它们隐藏在自定义布局后面。我尝试过在UITabBarController中重写size forChildContentContainer,尝试过更新底部布局参考线,结果为Nothing。我需要调整UITabBarController的容器视图框架的大小。
1.再次尝试#1,但尝试通过increasing the size of UITabBar解决内容隐藏在它后面的问题,然后使用ImageInset on every TabBarItem将其关闭,并将我的自定义视图添加到UITabBar顶部。效果不是很好。有时我会想隐藏我的自定义视图。

  1. UITabBarController作为根,每个子级都是一个ViewController,具有容器视图+我的自定义视图:

    但是现在我的自定义视图有多个示例在浮动。如果我想改变它的标签,必须改变它到所有视图。或者隐藏,等等。
    1.重写UITabBarController的UITabBar属性并返回我的自定义UITabBar(用xib扩展),该UITabBar包含UITabBar +我的自定义视图。**问题:**可能是所有尝试中最令人沮丧的尝试。如果用class MyCustomTabBar : UITabBar {}的示例重写该属性,则没有选项卡显示!是的,我将myCustomTabBar的委托设置为self
    倾向于#3,但在寻找更好的解决方案。
oaxa6hgo

oaxa6hgo1#

如果你子类化UITabBarController并以编程方式添加视图,这实际上非常容易。使用这种技术自动支持选项卡栏的旋转和大小更改,而不管你使用的是哪个版本。

class CustomTabBarController: UITabBarController {
  override func viewDidLoad() {
    super.viewDidLoad()

    //...do some of your custom setup work
    // add a container view above the tabBar
    let containerView = UIView()
    containerView.backgroundColor = .red
    view.addSubview(containerView)
    containerView.translatesAutoresizingMaskIntoConstraints = false
    containerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
    containerView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true

    // anchor your view right above the tabBar
    containerView.bottomAnchor.constraint(equalTo: tabBar.topAnchor).isActive = true

    containerView.heightAnchor.constraint(equalToConstant: 50).isActive = true
  }
}
dohp0rv5

dohp0rv52#

我拿到了!

实际上,我增加了原始UITabBar的大小以容纳自定义视图(并缩小了上面的视图控制器的框架),然后在其顶部添加了一个复制的UITabBar+自定义视图。
下面是我所要做的事情,我上传了一个功能示例,可以是found in this repo

class TabBarViewController: UITabBarController {

    var currentlyPlaying: CurrentlyPlayingView!
    static let maxHeight = 100
    static let minHeight = 49
    static var tabbarHeight = maxHeight

    override func viewDidLoad() {
        super.viewDidLoad()

        currentlyPlaying = CurrentlyPlayingView(copyFrom: tabBar)
        currentlyPlaying.tabBar.delegate = self

        view.addSubview(currentlyPlaying)
        tabBar.isHidden = true
    }
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        currentlyPlaying.tabBar.items = tabBar.items
        currentlyPlaying.tabBar.selectedItem = tabBar.selectedItem
    }
    func hideCurrentlyPlaying() {
        TabBarViewController.tabbarHeight = TabBarViewController.minHeight
        UIView.animate(withDuration: 0.5, animations: {
            self.currentlyPlaying.hideCustomView()
            self.updateSelectedViewControllerLayout()
        })
    }
    func updateSelectedViewControllerLayout() {
        tabBar.sizeToFit()
        tabBar.sizeToFit()
        currentlyPlaying.sizeToFit()
        view.setNeedsLayout()
        view.layoutIfNeeded()
        viewControllers?[self.selectedIndex].view.setNeedsLayout()
        viewControllers?[self.selectedIndex].view.layoutIfNeeded()
    }
}

extension UITabBar {

    open override func sizeThatFits(_ size: CGSize) -> CGSize {
        var sizeThatFits = super.sizeThatFits(size)
        sizeThatFits.height = CGFloat(TabBarViewController.tabbarHeight)
        return sizeThatFits
    }
}
ql3eal8s

ql3eal8s3#

从iOS 11开始,这变得简单了一些。当你添加视图时,你可以执行以下操作:

viewControllers?.forEach {
   $0.additionalSafeAreaInsets = UIEdgeInsets(
      top: 0, 
      left: 0,
      bottom: yourView.height,
      right: 0
   )
}
6xfqseft

6xfqseft4#

你把它放在一个 Package 器视图控制器中的想法是好的,但是这只会导致开销(更多的视图控制器加载到内存中),以及当你以后想改变代码时的问题。如果你想让这个条总是显示在你的UITabBarController上,那么你应该把它添加在那里。
你应该子类化UITabBarController并从一个nib加载自定义栏,这样你就可以访问标签栏(这样你就可以把你的栏正确地放在它上面),而且你只需要加载一次(这解决了你在每个标签上都有不同栏的问题)。
至于您的视图不对自定义栏的大小做出React,我不知道您如何才能做到这一点,但我最好的建议是使用一个公共变量和通知,您可以在各个选项卡中听到这些通知。
然后,可以使用该值修改底部约束。

yqyhoc1h

yqyhoc1h5#

除了使用UITabBar或容器vc之外,您还可以考虑将App Delegate中的视图添加到主窗口中,如以下帖子所示:
View floating above all ViewControllers
因为你的视图是围绕着标签栏的,所以在应用程序代理中创建它是完全可以的。
通过将浮动视图设置为应用程序委托的属性,您可以随时从应用程序委托单例访问浮动视图,这样就可以轻松地控制它在代码的任何地方的可见性。
通过改变浮动视图和超视图窗口之间的约束常数,可以调整视图的位置,从而较好地响应方向的变化。
另一种(类似的)方法是让浮动视图成为另一个类似于uid按钮的窗口。

chhqkbe1

chhqkbe16#

除非我误解了,您可以从UITabBarController类创建一个自定义视图,然后将其插入上方并将其约束到tabBar对象,该对象是与控制器关联的tabBar。
因此,从UITabBarController类创建自定义视图

class CustomTabBarController: UITabBarController {
    var customView: UIView = {
            let bar = UIView()
            bar.backgroundColor = .white
            bar.translatesAutoresizingMaskIntoConstraints = false
            return bar
        }()

在viewDidLoad()中,将自定义视图添加到UITabBarController的视图对象中,并将其放置在tabBar对象的上方

override func viewDidLoad() {
        super.viewDidLoad()
        
        ...

        self.view.insertSubview(customView, aboveSubview: tabBar)

然后在你的自定义视图被添加为子视图后,添加约束以使其正确定位。这也应该在viewDidLoad()中完成,但只能在你的视图被插入之后。

self.view.addConstraints([
            NSLayoutConstraint(item: customView, attribute: .leading, relatedBy: .equal, toItem: tabBar, attribute: .leading, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: customView, attribute: .trailing, relatedBy: .equal, toItem: tabBar, attribute: .trailing, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: customView, attribute: .top, relatedBy: .equal, toItem: tabBar, attribute: .top, multiplier: 1, constant: -50),
            NSLayoutConstraint(item: customView, attribute: .bottom, relatedBy: .equal, toItem: tabBar, attribute: .top, multiplier: 1, constant: 0)
            ])

有很多创造性的方法可以设置约束来完成你想要的任务,但是上面的约束应该在你的tabBar上附加一个高度为50的视图。

uttx8gqw

uttx8gqw7#

1.使视图的框架具有标签栏的高度,并将其置于顶部,2. set tabBar hidden为true。

相关问题