-2.7 C
New York
Wednesday, January 8, 2025

ios – The best way to make touchable view behind navigation bar?


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

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles