View on Top of UITabBar

筅森魡賤 提交于 2019-12-03 08:26:28

问题


Similar to what the Spotify or Apple Music app does when a song is playing, it places a custom view on top of the UITabBar:

Solutions I've tried:

  1. UITabBarController in a ViewController with a max-sized Container View, and the custom view on top of the Container View49pt above the Bottom Layout Guide: Problem: Any content in ViewControllers embedded in the UITabBarController constrained to the bottom don't show because they're hidden behind the custom layout. I've tried overriding size forChildContentContainer in UITabBarController, tried updating the bottom layout guide, Nothing. I need to resize the frame of container view of the UITabBarController.

  2. Tried #1 again, but tried solving the problem of content hiding behind it by increasing the size of UITabBar, and then using ImageInset on every TabBarItem to bring it down, and adding my custom view on top of the UITabBar. Hasn't worked really well. There are going to be times when I want to hide my custom view.

  3. UITabBarController as root, with each children being a ViewController with a Container View + my custom view: But now I have multiple instances of my custom view floating around. If I want to change a label on it, have to change it to all views. Or hide, etc.

  4. Override the UITabBar property of UITabBarController and return my custom UITabBar (inflated it with a xib) that has a UITabBar + my custom view. Problem: Probably the most frustrating attempt of all. If you override that property with an instance of class MyCustomTabBar : UITabBar {}, no tab shows up! And yes, I set the delegate of myCustomTabBar to self.

Leaning towards #3, but looking for a better solution.


回答1:


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



回答2:


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



回答3:


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.




回答4:


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.




回答5:


  1. Make the view's frame with the height of tab bar and brings it to top, 2. set tabBar hidden is true.


来源:https://stackoverflow.com/questions/42384470/view-on-top-of-uitabbar

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!