I take advantage of this code to create navigation bar with customized buttons:
override func viewDidLoad() {
tremendous.viewDidLoad()
navigationController?.navigationBar.backgroundColor = .clear
navigationItem.setHidesBackButton(true, animated: false)
rightButtonsImagesArrayNormal = ["gear","unmute"]
rightButtonsImagesArraySelected = ["gear","mute"]
navigationController?.navigationBar.addSubview(rightStackView)
setupNavigationBarButtonConstraint()
setupRightButtons()
}
func setupNavigationBarButtonConstraint() {
rightStackView.topAnchor.constraint(equalTo: (navigationController?.navigationBar.topAnchor)!, fixed: 8.0).isActive = true
rightStackView.bottomAnchor.constraint(equalTo: (navigationController?.navigationBar.bottomAnchor)!, fixed: -8.0).isActive = true
rightStackView.trailingAnchor.constraint(equalTo: (navigationController?.navigationBar.trailingAnchor)!, fixed: -SafeArea().proper()).isActive = true
}
func setupRightButtons() {
var configuration = UIButton.Configuration.plain()
configuration.baseBackgroundColor = UIColor.clear
barButton = UIButton(configuration: configuration, primaryAction: nil)
let handler: UIButton.ConfigurationUpdateHandler = { button in
change button.state {
case .regular: button.configuration?.picture = UIImage(named: self.rightButtonsImagesArrayNormal[index-1])
case .chosen: button.configuration?.picture = UIImage(named: self.rightButtonsImagesArraySelected[index-1])
default: break
}
}
barButton.configurationUpdateHandler = handler
barButton.tag = index
barButton.widthAnchor.constraint(equalToConstant: CGFloat(navigationBarButtonHeight)).isActive = true
barButton.heightAnchor.constraint(equalToConstant: CGFloat(navigationBarButtonHeight)).isActive = true
barButton.addTarget(self, motion: #selector(self.rightBarButtonAction), for: .touchUpInside)
rightStackView.addArrangedSubview(barButton)
rightStackView.widthAnchor.constraint(equalToConstant: CGFloat(((navigationBarButtonHeight+16)*rightButtonsImagesArrayNormal.rely) - 16)).isActive = true
}
I take advantage of:
navigationController?.navigationBar.isUserInteractionEnabled = false
to make view behind my navigation bar touchable however on this case my barButton
inside rightStackView
turn out to be untouchable and I can not use barButton
. I do that:
barButton.isUserInteractionEnabled = true
rightStackView.isUserInteractionEnabled = true
however it’s would not repair the issue. The best way to repair it?
Full code as @HangarRash really useful:
class ViewController: UIViewController {
var navigationBarHeight = Float()
var rightBarButtonSize = Float()
var rightButtonsImagesArrayNormal = [""]
var rightButtonsImagesArraySelected = [""]
lazy var rightStackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .horizontal
stackView.spacing = 16
stackView.alignment = .fill
stackView.distribution = .equalSpacing
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
var barButton: UIButton = {
let button = UIButton()
button.layer.shadowColor = UIColor.black.withAlphaComponent(0.5).cgColor
button.layer.shadowOffset = CGSize.zero
button.layer.shadowOpacity = 0.2
button.layer.shadowRadius = 3
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
func setupNavigationBar() {
defaultHeight = (navigationController?.navigationBar.body.measurement.top)!
navigationItem.carry out(NSSelectorFromString(["_", "set", "Bottom", "Palette", ":"].joined()), with: NavigationBarCustomHeight().top())
navigationController?.navigationBar.backgroundColor = .clear
navigationController?.navigationBar.isUserInteractionEnabled = false
navigationItem.setHidesBackButton(true, animated: false)
rightButtonsImagesArrayNormal = ["gear","unmute"]
rightButtonsImagesArraySelected = ["gear","mute"]
navigationController?.navigationBar.addSubview(rightStackView)
setupNavigationBarButtonConstraint()
setupRightButtons()
}
func setupNavigationBarButtonConstraint() {
rightStackView.topAnchor.constraint(equalTo: (navigationController?.navigationBar.topAnchor)!, fixed: 8.0).isActive = true
rightStackView.bottomAnchor.constraint(equalTo: (navigationController?.navigationBar.bottomAnchor)!, fixed: -8.0).isActive = true
rightStackView.trailingAnchor.constraint(equalTo: (navigationController?.navigationBar.trailingAnchor)!, fixed: -32).isActive = true
}
func setupRightButtons() {
for index in 1...rightButtonsImagesArrayNormal.rely {
var configuration = UIButton.Configuration.plain()
configuration.baseBackgroundColor = UIColor.clear
barButton = UIButton(configuration: configuration, primaryAction: nil)
let handler: UIButton.ConfigurationUpdateHandler = { button in
change button.state {
case .regular: button.configuration?.picture = UIImage(named: self.rightButtonsImagesArrayNormal[index-1])
case .chosen: button.configuration?.picture = UIImage(named: self.rightButtonsImagesArraySelected[index-1])
default: break
}
}
barButton.configurationUpdateHandler = handler
barButton.tag = index
barButton.widthAnchor.constraint(equalToConstant: CGFloat(navigationBarButtonHeight)).isActive = true
barButton.heightAnchor.constraint(equalToConstant: CGFloat(navigationBarButtonHeight)).isActive = true
barButton.addTarget(self, motion: #selector(self.rightBarButtonAction), for: .touchUpInside)
rightStackView.addArrangedSubview(barButton)
rightStackView.widthAnchor.constraint(equalToConstant:
CGFloat(((navigationBarButtonHeight+16)*rightButtonsImagesArrayNormal.rely) - 16)).isActive = true
}
}
override func viewDidLoad() {
tremendous.viewDidLoad()
setupNavigationBar()
}
}
var defaultHeight = CGFloat()
var navigationBarHeight = 80
var navigationBarButtonHeight = 64
class NavigationBarCustomHeight: UIViewController {
func top() -> AnyObject {
let contentView = UIView()
contentView.body.measurement.top = CGFloat(navigationBarHeight) - defaultHeight
let _UINavigationBarPalette = NSClassFromString(["_", "UI", "Navigation", "Bar", "Palette"].joined()) as! UIView.Kind
let palette = _UINavigationBarPalette.carry out(NSSelectorFromString("alloc"))
.takeUnretainedValue()
.carry out(NSSelectorFromString("initWithContentView:"), with: contentView)
.takeUnretainedValue()
return palette
}
}