View on Top of UITabBar

后端 未结 7 1775
慢半拍i
慢半拍i 2021-02-02 16:03

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. UITa

相关标签:
7条回答
  • 2021-02-02 16:44

    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
        }
    }
    
    0 讨论(0)
  • 2021-02-02 16:46

    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.

    0 讨论(0)
  • 2021-02-02 16:50

    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
      }
    }
    
    0 讨论(0)
  • 2021-02-02 16:56

    Since iOS 11 this became a little easier. When you add your view, you can do the following:

    viewControllers?.forEach {
       $0.additionalSafeAreaInsets = UIEdgeInsets(
          top: 0, 
          left: 0,
          bottom: yourView.height,
          right: 0
       )
    }
    
    0 讨论(0)
  • 2021-02-02 16:57

    Unless I've misunderstood, you could create a custom view from your UITabBarController class. You can then insert it above and constrain it to the tabBar object, which is the tabBar association with the controller.

    So from your UITabBarController class, create your custom view

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

    In viewDidLoad() add your custom view to the UITabBarController's view object and place it above the tabBar object

    override func viewDidLoad() {
            super.viewDidLoad()
    
            ...
    
            self.view.insertSubview(customView, aboveSubview: tabBar)
    

    Then after your custom view is added as a subView, add constraints so it's positioned correctly. This should also be done in viewDidLoad() but only after your view is inserted.

    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)
                ])
    

    There's a bunch of creative ways you can setup constraints to do what you want, but the constraints above should attach a view above your tabBar with a height of 50.

    0 讨论(0)
  • 2021-02-02 16:57
    1. Make the view's frame with the height of tab bar and brings it to top, 2. set tabBar hidden is true.
    0 讨论(0)
提交回复
热议问题