0

I implemented header(UIView) for my view controller but i cannot add target for the button inside at the UIView. I believe this is very understandable for everyone but i can add more detail if you want

MY View Controller Code inside loadView()

let headerViewModel = HeaderViewModel(title: "Farmers", helpAction:  {self.navigationController?.popViewController(animated: true) // when debugging this        //line doesn't work when adding })
let headerView = HeaderView(viewModel: headerViewModel)

MY Header UIView Code

import UIKit

protocol HeaderViewModelProtocol {
    var title: String { get }
    var color: UIColor { get }
    var imageName: String? { get }
    var backAction: (()->Void)? { get set}
    var helpAction: (()->Void)? { get set}
}

struct HeaderViewModel: HeaderViewModelProtocol {
    let title: String
    var color: UIColor = UIColor.white
    var imageName: String?
    var backAction: (() -> Void)?
    var helpAction: (() -> Void)?
}

class HeaderView: UIView {
    
    let viewModel: HeaderViewModelProtocol
    private var layer0: CAGradientLayer!
    
    var backButton: UIButton = {
        let button = UIButton()
            button.frame = CGRect(x: 0, y: 0, width: 10, height: 10)
            button.addTarget(HeaderView.self, action: #selector(tapBack), for: .touchUpInside)
            button.backgroundColor = UIColor.red
            button.tag=5
            button.translatesAutoresizingMaskIntoConstraints = false
            button.backgroundColor = .clear
            button.tintColor = .white
            button.setImage(UIImage(named: "back"), for: .normal)
            return button
    }()
    
    
    var helpButton: UIButton = {
        let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.backgroundColor = .clear
        button.setImage(UIImage(named: "plus"), for: .normal)
        button.tintColor = .white
        return button
    }()
    init(viewModel: HeaderViewModelProtocol) {
        self.viewModel = viewModel
        super.init(frame: .zero)
        loadView()
    }
    func loadView() {
        if viewModel.backAction != nil {
            backButton.addTarget(self, action: #selector(tapBack), for: .touchUpInside)
            
            addSubview(backButton)
            
            backButton.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 30).isActive = true
            backButton.topAnchor.constraint(equalTo: topAnchor, constant: 36).isActive = true
            backButton.widthAnchor.constraint(equalToConstant: 22).isActive = true
            backButton.heightAnchor.constraint(equalToConstant: 36).isActive = true
        }
        
        if viewModel.helpAction != nil {
            helpButton.addTarget(self, action: #selector(tapHelp), for: .touchUpInside)
            addSubview(helpButton)
            
            helpButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -30).isActive = true
            helpButton.topAnchor.constraint(equalTo: topAnchor, constant: 36).isActive = true
            helpButton.widthAnchor.constraint(equalToConstant: 22).isActive = true
            helpButton.heightAnchor.constraint(equalToConstant: 36).isActive = true
        }
    }

    @objc func tapBack() {
        viewModel.backAction?()
    }
    
    @objc func tapHelp() {
        viewModel.helpAction?()
    }
}

Thanks in advance everyone! You can contact me !

  • You didn't show us how you are using `headerView` ... safe bet, though, is that you are not giving it any **height** - so the button is *visible* but is outside the frame of `headerView`. If you set `headerView.backgroundColor = .cyan` it is likely you won't see any cyan color at all. Or, if you do, it won't extend to the bottom of `helpButton`. – DonMag Aug 08 '23 at 12:28
  • i simply add view.addSubview(headerView) and i give height 140 to headerview – Burak Demir Aug 09 '23 at 14:44

1 Answers1

0

Your comment says you "give height 140 to headerview" ... but you don't show how you're doing that, so I still think your button is ending up outside the view bounds.

Here is your code, with minor modifications:

protocol HeaderViewModelProtocol {
    var title: String { get }
    var color: UIColor { get }
    var imageName: String? { get }
    var backAction: (()->Void)? { get set}
    var helpAction: (()->Void)? { get set}
}

struct HeaderViewModel: HeaderViewModelProtocol {
    let title: String
    var color: UIColor = UIColor.white
    var imageName: String?
    var backAction: (() -> Void)?
    var helpAction: (() -> Void)?
}

class HeaderView: UIView {
    
    let viewModel: HeaderViewModelProtocol
    private var layer0: CAGradientLayer!
    
    var backButton: UIButton = {
        let button = UIButton()
        button.frame = CGRect(x: 0, y: 0, width: 10, height: 10)
        button.addTarget(HeaderView.self, action: #selector(tapBack), for: .touchUpInside)
        button.backgroundColor = UIColor.red
        button.tag=5
        button.translatesAutoresizingMaskIntoConstraints = false
        button.backgroundColor = .clear
        button.tintColor = .white
        button.setImage(UIImage(named: "back"), for: .normal)

        // during development, use a background color so we can easily see the frame
        button.backgroundColor = .red

        return button
    }()
    
    
    var helpButton: UIButton = {
        let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.backgroundColor = .clear
        button.setImage(UIImage(named: "plus"), for: .normal)
        button.tintColor = .white

        // during development, use a background color so we can easily see the frame
        button.backgroundColor = .blue

        return button
    }()
    init(viewModel: HeaderViewModelProtocol) {
        self.viewModel = viewModel
        super.init(frame: .zero)
        loadView()
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    func loadView() {
        if viewModel.backAction != nil {
            backButton.addTarget(self, action: #selector(tapBack), for: .touchUpInside)
            
            addSubview(backButton)
            
            backButton.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 30).isActive = true
            backButton.topAnchor.constraint(equalTo: topAnchor, constant: 36).isActive = true
            backButton.widthAnchor.constraint(equalToConstant: 22).isActive = true
            backButton.heightAnchor.constraint(equalToConstant: 36).isActive = true

            // if you want these UI elements to determine the height
            //backButton.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -36).isActive = true
        }
        
        if viewModel.helpAction != nil {
            helpButton.addTarget(self, action: #selector(tapHelp), for: .touchUpInside)
            addSubview(helpButton)
            
            helpButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -30).isActive = true
            helpButton.topAnchor.constraint(equalTo: topAnchor, constant: 36).isActive = true
            helpButton.widthAnchor.constraint(equalToConstant: 22).isActive = true
            helpButton.heightAnchor.constraint(equalToConstant: 36).isActive = true

            // if you want these UI elements to determine the height
            //helpButton.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -36).isActive = true
        }
        
    }
    
    @objc func tapBack() {
        print("back tapped")
        viewModel.backAction?()
    }
    
    @objc func tapHelp() {
        print("help tapped")
        viewModel.helpAction?()
    }
}

and a sample view controller to show it working:

class HeaderViewVC: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()

        let headerViewModel = HeaderViewModel(title: "Farmers", helpAction:  {
            print("Farmers Help Action")
            self.navigationController?.popViewController(animated: true) // when debugging this        //line doesn't work when adding })
        })
        let headerView = HeaderView(viewModel: headerViewModel)
        
        headerView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(headerView)
        
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            headerView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
            headerView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
            headerView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
            headerView.heightAnchor.constraint(equalToConstant: 140.0),
        ])
    
        // during development... makes it easy to see the view framing
        headerView.backgroundColor = .cyan
        
    }
    
}

Run that, and you'll see that you get:

help tapped
Farmers Help Action

output to the debug console when you tap the button.

Compare this code to your actual code, and see what's different.

DonMag
  • 69,424
  • 5
  • 50
  • 86