
This video is only available to subscribers. Start a subscription today to get access to this and 469 other videos.
Player Bar Part 2
This episode is part of a series: Making a Podcast App From Scratch.
Creating a Custom Tab Bar
We will start by creating a class for our custom tab bar along with its controller. We will name it "ExtendedTabBarController" and "ExtendedTabBar" and hook them together in the storyboard. When the user taps on the present player button from our player bar, we will present the player from the ExtendedTabBarController
. To do this, we will set the presentationRootController
on the player bar to self
when the tab bar controller is initialized.
import UIKit
class ExtendedTabBarController : UITabBarController {
override func awakeFromNib() {
super.awakeFromNib()
let player = PlayerViewController.shared
player.presentationRootController = self
let playerBar = player.playerBar
// install this in the tab bar
(tabBar as? ExtendedTabBar)?.playerBar = playerBar
}
}
Next, we will set the player bar instance from the controller and install it in the view hierarchy of the tab bar. In the event we ever wanted to call this setter twice, we will use willSet
to remove any previous view before installing the new one.
class ExtendedTabBar : UITabBar {
var playerBar: PlayerBar? {
willSet {
if newValue != playerBar {
playerBar?.removeFromSuperview()
}
}
didSet {
if let playerBar = playerBar {
install(playerBar: playerBar)
}
}
}
}
In the tab bar controller, we will have an optional typecast for our extended tab bar.
// install this in the tab bar
(tabBar as? ExtendedTabBar)?.playerBar = playerBar
Installation of the Tab Bar
Finally, we will install the tab bar in our ExtendedTabBar
. To avoid the conflicting constraints based on the current size of the storyboard we will set translatesAutoresizingMaskIntoConstraints
to false. We will now set the constraints for playerBar. We will set out tab bar high so it accommodates the player bar.
var playerBarHeight: CGFloat = 0
private func install(playerBar: PlayerBar) {
playerBarHeight = playerBar.frame.height
addSubview(playerBar)
playerBar.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
playerBar.heightAnchor.constraint(equalToConstant: playerBarHeight),
playerBar.leadingAnchor.constraint(equalTo: leadingAnchor),
playerBar.trailingAnchor.constraint(equalTo: trailingAnchor),
playerBar.topAnchor.constraint(equalTo: topAnchor)
])
}
To determine the size to be rendered by layout before we start playing the player, we will override the sizeThatFits
in our tab bar.
var playerBarVisible: Bool {
return playerBar?.isHidden == false
}
override func sizeThatFits(_ size: CGSize) -> CGSize {
let originalSize = super.sizeThatFits(size)
guard playerBarVisible else { return originalSize }
var modifiedSize = originalSize
modifiedSize.height += playerBarHeight
return modifiedSize
}
We now have to reposition the tab bar items back to where they would be in a normal height tab bar.
override func layoutSubviews() {
super.layoutSubviews()
guard playerBarVisible else { return }
for subview in subviews {
if let control = subview as? UIControl {
control.frame.origin.y += playerBarHeight
control.frame.size.height -= playerBarHeight
}
}
}
Debugging Tips for Nonresponding Buttons
To diagnose when buttons aren't tappable, we can check a few things:
1) We will check the User Interaction Enable for these buttons using View Debugger.
2) We will also check for the button is enabled and has target and action at run time.
3) Check if the button container is in view hierarchy to receive touch events. In this case, we will set the height of the button container equally to Stack View using a storyboard.