View on Top of UITabBar

◇◆丶佛笑我妖孽 提交于 2019-12-02 22:31:18

I got it!

In essence, I increased the size of the original UITabBar to accomodate a custom view (and to shrink the frame of the viewcontrollers above), and then adds a duplicate UITabBar + custom view right on top of it.

Here's the meat of what I had to do. I uploaded a functioning example of it and can be 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
    }
}

This is actually very easy if you subclass UITabBarController and add your view programmatically. Using this technique automatically supports rotation and size changes of the tab bar, regardless of which version you are on.

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

Your idea to put it in a wrapper viewcontroller is good, but it will only cause overhead (more viewcontrollers to load in memory), and issues when you want to change the code later on. If you want the bar to always show on your UITabBarController, then you should add it there.

You should subclass UITabBarController and load the custom bar from a nib. There you will have access to the tabbar (so you can place your bar correctly above it), and you will only load it in once (which solves your problem that you will face having a different bar on each tab).

As for your views not reacting to the size of the custom bar, I don't know how you can do that, but my best suggestion is to use a public variable and notifications that you listen to in your individual tabs.
You can then use that to change the bottom constraint.

Besides playing with UITabBar or container vc, you could also consider adding the view in the App Delegate to the main window like in following post:

View floating above all ViewControllers

Since your view is all around along with the Tab bar, it is totally ok to make it in the App Delegate.

You can always access the Floating view from App Delegate Singleton by making it a property of the App Delegate. It is easy then to control its visibility in anywhere of your code.

Changing constant of the Constraints between the Floating view and super view window can adjust the position of the view, thus handsomely respond to orientation changes.

Another(similar) approach is to make the floating view another window like the uid button.

  1. Make the view's frame with the height of tab bar and brings it to top, 2. set tabBar hidden is true.
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!