自定义HeaderView(UIView)内按钮添加Target无响应问题求助
自定义HeaderView内按钮Target不生效问题排查
我给ViewController实现了自定义HeaderView(UIView),但该UIView内的按钮添加的Target无法生效,调试时发现对应事件代码未执行。
相关代码
ViewController的loadView()代码
let headerViewModel = HeaderViewModel(title: "Farmers", helpAction: {self.navigationController?.popViewController(animated: true) // 调试时该行代码未执行 }) let headerView = HeaderView(viewModel: headerViewModel)
HeaderView实现代码
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?() } }
问题原因及修复方案
1. backButton初始化时错误绑定Target
问题:在backButton的闭包初始化代码中,将Target设置为HeaderView.self(类本身),但tapBack是实例方法,类无法响应实例方法的事件,直接导致按钮点击无响应。后续在loadView中重复添加的正确Target也会被初始的错误Target干扰。
修复:删除backButton初始化闭包中的错误Target绑定代码,只保留loadView中针对实例self的绑定:
var backButton: UIButton = { let button = UIButton() button.frame = CGRect(x: 0, y: 0, width: 10, height: 10) // 移除错误的Target绑定行 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 }()
2. (潜在问题)值类型ViewModel的闭包引用问题
问题:HeaderViewModel是struct(值类型),传入HeaderView时会发生值拷贝,若后续闭包引用的上下文被意外覆盖,可能导致闭包无法正确执行。
修复(可选):将HeaderViewModel改为class(引用类型),避免值拷贝带来的问题:
class HeaderViewModel: HeaderViewModelProtocol { let title: String var color: UIColor = UIColor.white var imageName: String? var backAction: (() -> Void)? var helpAction: (() -> Void)? init(title: String) { self.title = title } }
3. 验证HeaderView布局完整性
排查点:确保HeaderView被正确添加到ViewController的视图层级中,并且有明确的尺寸约束(比如设置heightAnchor),避免因父视图尺寸为0导致按钮超出交互区域。可以给HeaderView设置临时背景色,确认其布局范围是否符合预期。
内容的提问来源于stack exchange,提问作者Burak Demir
相关产品推荐
相关产品推荐

