iOS navigationItem 中带有 AutoLayout 的 CustomView 未收到点击

iOS CustomView With AutoLayout in navigationItem not receiving clicks

我为 navigationItem 创建了一个自定义视图,但不知何故它没有收到任何点击事件:

customView的代码如下

class CustomNavigationView: UIView {

let backButton: UIButton = {
    let button = UIButton(type: .custom)
    button.setImage(UIImage(named: "icon_back", in: Bundle.main, compatibleWith: nil), for: .normal)
    button.isUserInteractionEnabled = true
    return button
}()

var profileImage: UIImageView = {
    let imageView = UIImageView()
    imageView.image = UIImage(named: "icon_back", in: Bundle.main, compatibleWith: nil)
    return imageView
}()

var profileName: UILabel = {
    let label = UILabel()
    label.text = "No Name"
    label.font = UIFont(name: "HelveticaNeue", size: 16) ?? UIFont.systemFont(ofSize: 16)
    label.textColor = UIColor(red: 96, green: 94, blue: 94)
    return label
}()

var onlineStatusIcon: UIView = {
    let view = UIView()
    view.backgroundColor = UIColor(28, green: 222, blue: 20)
    return view
}()

var onlineStatusText: UILabel = {
    let label = UILabel()
    label.text = "Online"
    label.font = UIFont(name: "HelveticaNeue", size: 12) ?? UIFont.systemFont(ofSize: 12)
    label.textColor = UIColor(red: 113, green: 110, blue: 110)
    return label
}()

lazy var profileView: UIStackView = {
    let stackView = UIStackView(arrangedSubviews: [self.profileName, self.onlineStatusText])
    stackView.alignment = .fill
    stackView.axis = .vertical
    stackView.distribution = .fillEqually
    stackView.spacing = 2
    return stackView
}()

@objc func backButtonClicked(_ sender: UIButton) {
    print("Back Button click successfully")
}

private func setupConstraints() {
    self.addViewsForAutolayout(views: [backButton, profileImage, onlineStatusIcon, profileView])
    //Setup constraints
    backButton.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 5).isActive = true
    backButton.topAnchor.constraint(equalTo: self.topAnchor, constant: 10).isActive = true
    backButton.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -10).isActive = true
    backButton.widthAnchor.constraint(equalToConstant: 20).isActive = true

    profileImage.leadingAnchor.constraint(equalTo: backButton.trailingAnchor, constant: 20).isActive = true
    profileImage.topAnchor.constraint(equalTo: self.topAnchor, constant: 5).isActive = true
    profileImage.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -5).isActive = true
    profileImage.widthAnchor.constraint(equalToConstant: 35).isActive = true
    profileImage.layer.cornerRadius = 18
    profileImage.clipsToBounds = true

    onlineStatusIcon.bottomAnchor.constraint(equalTo: profileImage.bottomAnchor, constant: 0).isActive = true
    onlineStatusIcon.leadingAnchor.constraint(equalTo: profileImage.trailingAnchor, constant: -8).isActive = true
    onlineStatusIcon.widthAnchor.constraint(equalToConstant: 10).isActive = true
    onlineStatusIcon.heightAnchor.constraint(equalToConstant: 10).isActive = true
    onlineStatusIcon.layer.cornerRadius = 5
    onlineStatusIcon.clipsToBounds = true

    profileView.leadingAnchor.constraint(equalTo: profileImage.trailingAnchor, constant: 5).isActive = true
    profileView.topAnchor.constraint(equalTo: profileImage.topAnchor).isActive = true
    profileView.bottomAnchor.constraint(equalTo: profileImage.bottomAnchor).isActive = true

}

required init() {
    super.init(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: 40))
    setupConstraints()
    addButtonTarget()
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

func addButtonTarget() {
    // Setup button callback
    backButton.addTarget(self, action: #selector(backButtonClicked(_:)), for: .touchUpInside)

    print("Target added")
}
}

并且我将此视图设置为视图控制器中的 NavigationbarLeft 按钮项:

class ViewController:  UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()
    let customView = CustomNavigationView()
    self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: customView)
}
}

视图显示正确,但点击根本不起作用。 我使用视图调试来检查是否有其他层在此之上,这可能会导致问题,但不存在任何此类问题。 在使用调试点添加目标时,我还检查了 backButton 框架。

这个问题有解决办法吗。自动布局是否不适用于导航项中的自定义视图?或者有什么我想念的。

您可以 运行 上面的代码段,看看点击不起作用。

这似乎与自动布局有关。如果我对框架位置进行硬编码,则点击有效。

class CustomNavigationView: UIView {

let backButton: UIButton = {
    let button = UIButton(frame: CGRect(x: 5, y: 5, width: 30, height: 30))
    button.setImage(UIImage(named: "icon_back", in: Bundle.kommunicate, compatibleWith: nil), for: .normal)
    button.isUserInteractionEnabled = true
    return button
}()

var profileImage: UIImageView = {
    let imageView = UIImageView(frame: CGRect(x: 40, y: 5, width: 30, height: 30))
    imageView.image = UIImage(named: "icon_back", in: Bundle.kommunicate, compatibleWith: nil)
    return imageView
}()

var profileName: UILabel = {
    let label = UILabel(frame: CGRect(x: 80, y: 5, width: 50, height: 15))
    label.text = "No Name"
    label.font = UIFont(name: "HelveticaNeue", size: 16) ?? UIFont.systemFont(ofSize: 16)
    label.textColor = UIColor(red: 96, green: 94, blue: 94)
    return label
}()

var onlineStatusIcon: UIView = {
    let view = UIView(frame: CGRect(x: 65, y: 30, width: 10, height: 10))
    view.backgroundColor = UIColor(28, green: 222, blue: 20)
    return view
}()

var onlineStatusText: UILabel = {
    let label = UILabel(frame: CGRect(x: 80, y: 25, width: 50, height: 10))
    label.text = "Online"
    label.font = UIFont(name: "HelveticaNeue", size: 12) ?? UIFont.systemFont(ofSize: 12)
    label.textColor = UIColor(red: 113, green: 110, blue: 110)
    return label
}()

lazy var profileView: UIStackView = {
    let stackView = UIStackView(arrangedSubviews: [self.profileName, self.onlineStatusText])
    stackView.alignment = .fill
    stackView.axis = .vertical
    stackView.distribution = .fillEqually
    stackView.spacing = 2
    return stackView
}()

@objc func backButtonClicked(_ sender: UIButton) {
    print("Back button is successfully called")
}

private func setupConstraints() {
    self.addSubview(backButton)
    self.addSubview(profileImage)
    self.addSubview(onlineStatusIcon)
    self.addSubview(profileView)
}

required init() {
    super.init(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: 40))
    setupConstraints()
    addButtonTarget()
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

func addButtonTarget() {
    // Setup button callback
    backButton.addTarget(self, action: #selector(backButtonClicked(_:)), for: .touchUpInside)

    print("Target added")
}
}

问题出在您添加的手动添加的约束上。 使用视图调试器 CustomNavigationView 添加到栏后的宽度为 0.

为了强制容器展开,在setupConstraints()中添加如下约束:

profileView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true

现在容器展开以匹配其内容,触摸事件应该按预期传播到按钮。