ios - UIKit-Swift 自定义 UIButton 不会触发点击 Action

标签 ios swift xcode uikit uilabel

我已经定义了一个“类似 RadioButton”的 UIButton。为了实现这一点,我在 UIButton 中添加了一个 subview ,我在 .touchUpInside 上更改了它的颜色事件。
问题是没有触发 Action 。
这是我的 RadioButton 的代码:

    final class RadioButton: UIButton {
    let stateView = UIView()
    var isActive: Bool = false {
        didSet {
            if isActive == true {
                stateView.backgroundColor = #colorLiteral(red: 0, green: 0.5839999914, blue: 0.5289999843, alpha: 1)
            } else {
                stateView.backgroundColor = .clear
            }
        }
    }
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    convenience init() {
        self.init(frame: .zero)
        configure()
    }
    
    private func configureColorSubview() {
        stateView.backgroundColor = .white
        stateView.isUserInteractionEnabled = false
        stateView.layer.cornerRadius = 10
        stateView.translatesAutoresizingMaskIntoConstraints = false
        stateView.widthAnchor.constraint(equalToConstant: 20).isActive = true
        stateView.heightAnchor.constraint(equalToConstant: 20).isActive = true
        stateView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
        stateView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
    }
    
    private func configure() {
        isUserInteractionEnabled = true
        addSubview(stateView)
        configureColorSubview()
        stateView.layer.zPosition = -1
        sendSubviewToBack(stateView)
        layer.cornerRadius = 20
        layer.borderWidth = 2
        layer.borderColor = UIColor.darkGray.cgColor
        translatesAutoresizingMaskIntoConstraints = false
        widthAnchor.constraint(equalToConstant: 40).isActive = true
        heightAnchor.constraint(equalToConstant: 40).isActive = true
    }
}
这是 RadioButton 用标签包装的 View 的代码:
final class RadioButtonLabelView: UILabel {
    
    let radioBtn: RadioButton = {
        let r = RadioButton()
        return r
    }()
    let label: UILabel = {
        let label = UILabel()
        let text = "Text"
        let attributedText = NSMutableAttributedString(string: text, attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 22, weight: .semibold), NSAttributedString.Key.foregroundColor: UIColor.black])
        label.attributedText = attributedText
        return label
    }()
    let stack: UIStackView = {
        let stack = UIStackView()
        stack.axis = .horizontal
        stack.distribution = .fill
        stack.spacing = 20
        return stack
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    convenience init(text: String) {
        self.init(frame: .zero)
        setupView(text: text)
        
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupView(text: String) {
        addSubview(stack)
        stack.addArrangedSubview(radioBtn)
        stack.addArrangedSubview(label)
        label.text = text
        stack.anchor(topAnchor: topAnchor, trailingAnchor: trailingAnchor, bottomAnchor: bottomAnchor, leadingAnchor: leadingAnchor)
    }
}
这是最终的模态视图代码:
final class SelectHourModalView: UIViewController {
    lazy var buttonToOptionsConstraint: NSLayoutConstraint = button.topAnchor.constraint(greaterThanOrEqualTo: radioButtons.bottomAnchor, constant: 50)
    lazy var buttonToPicker: NSLayoutConstraint = button.topAnchor.constraint(greaterThanOrEqualTo: datePicker.bottomAnchor, constant: 50)
    var isShowPicker: Bool = false {
        didSet {
            if isShowPicker {
                showPicker()
            } else {
                hidePicker()
            }
        }
    }
    
    let radioButtons: RadioButtonOptionsView = {
        let rb = RadioButtonOptionsView()
        return rb
    }()
    let datePicker: UIDatePicker = {
        let date = UIDatePicker()
        date.datePickerMode = .dateAndTime
        date.setValue(UIColor.black, forKeyPath: "textColor")
        return date
    }()
    let button: IoTaxiBtn = {
        let button = IoTaxiBtn(text: "Seleccionar", color: #colorLiteral(red: 0, green: 0.5839999914, blue: 0.5289999843, alpha: 1), insets: UIEdgeInsets(top: 10, left: 0, bottom: 8, right: 0), font: UIFont.systemFont(ofSize: 25, weight: .bold), corner: 3)
        button.shadow(color: UIColor.gray.cgColor, opacity: 1, offset: CGSize(width: .zero, height: 2), radius: 5)
        button.isUserInteractionEnabled = false
        return button
    }()
    private lazy var rbCollection: [RadioButtonLabelView] = {
        let rbc = [radioButtons.btnLabelNow, radioButtons.btnLabel1, radioButtons.btnLabel20, radioButtons.btnLabel30, radioButtons.btnLabelCustom]
        return rbc
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupFront()
        setActions()
        initialViewConfiguration()
    }
    
    private func setupFront() {
        view.backgroundColor = .white
        [radioButtons, datePicker, button].forEach {
            view.addSubview($0)
        }
        radioButtons.anchor(topAnchor: view.topAnchor, trailingAnchor: view.trailingAnchor, bottomAnchor: nil, leadingAnchor: view.leadingAnchor, padding: .init(top: 15, left: 20, bottom: .zero, right: 20))
        datePicker.anchor(topAnchor: radioButtons.bottomAnchor, trailingAnchor: view.trailingAnchor, bottomAnchor: nil, leadingAnchor: view.leadingAnchor, padding: .init(top: 20, left: 20, bottom: .zero, right: 20), size: .init(width: .zero, height: 190))
        button.anchor(topAnchor: nil, trailingAnchor: view.trailingAnchor, bottomAnchor: nil, leadingAnchor: view.leadingAnchor, padding: .init(top: .zero, left: 20, bottom: .zero, right: 20))
        buttonToPicker.isActive = true
        buttonToOptionsConstraint.isActive = false
    }
    
    private func setActions() {
        rbCollection.forEach {
            $0.radioBtn.addTarget(self, action: #selector(setHour), for: .touchUpInside)
        }
        print(radioButtons.btnLabelCustom.radioBtn.actions(forTarget: self, forControlEvent: .touchUpInside) ?? ["Nada"])
    }
    
    @objc private func setHour(_ sender: RadioButton) {
        print("tap")
        rbCollection.forEach {
            $0.radioBtn.isActive = false
        }
        sender.isActive.toggle()
    }
}

//MARK: - Constraints management
//TODO: Animations
private extension SelectHourModalView {
    func initialViewConfiguration() {
        radioButtons.btnLabelCustom.radioBtn.isActive = true
        isShowPicker = true
    }
    func showPicker() {
        buttonToOptionsConstraint.isActive = false
        buttonToPicker.isActive = true
        datePicker.isHidden = false
    }
    func hidePicker() {
        buttonToPicker.isActive = true
        buttonToOptionsConstraint.isActive = true
        datePicker.isHidden = true
    }
}

final class RadioButtonOptionsView: UIView {
    
    let btnLabelNow: RadioButtonLabelView = {
       let btnLabel = RadioButtonLabelView(text: "Recógeme ahora")
        return btnLabel
    }()
    let btnLabel20: RadioButtonLabelView = {
       let btnLabel = RadioButtonLabelView(text: "Recógeme en 20 minutos")
        return btnLabel
    }()
    let btnLabel30: RadioButtonLabelView = {
       let btnLabel = RadioButtonLabelView(text: "Recógeme en 30 minutos")
        return btnLabel
    }()
    let btnLabel1: RadioButtonLabelView = {
       let btnLabel = RadioButtonLabelView(text: "Recógeme en una hora")
        return btnLabel
    }()
    let btnLabelCustom: RadioButtonLabelView = {
       let btnLabel = RadioButtonLabelView(text: "Hora personalizada")
        return btnLabel
    }()

    let stackContainer: UIStackView = {
        let stack = UIStackView()
        stack.axis = .vertical
        stack.distribution = .fill
        stack.spacing = 8
        return stack
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupView() {
        addSubview(stackContainer)
        [btnLabelNow, btnLabel20, btnLabel30, btnLabel1, btnLabelCustom].forEach {
            stackContainer.addArrangedSubview($0)
        }
        stackContainer.anchor(topAnchor: topAnchor, trailingAnchor: trailingAnchor, bottomAnchor: bottomAnchor, leadingAnchor: leadingAnchor)
    }
}
这是 UI 调试器:
enter image description here
问题是什么?堆栈 View 与 RadioButton 具有相同的高度,并且 RadioButton 内的 stateView 具有 -1 zIndex 并且用户不可交互。

最佳答案

继承 RadioButtonLabelViewUIView而不是 UILabel将解决您的问题

final class RadioButtonLabelView: UIView {
    //....
 }

关于ios - UIKit-Swift 自定义 UIButton 不会触发点击 Action ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62641615/

相关文章:

ios - 尝试传回 userInfo 时 NSNotification 在 Swift 中中断

ios - 如何一个一个地播放多个音频文件

ios - 是否可以在同一个应用程序中同时运行 AFNetworking 和 Alamofire?

objective-c - 引入 if() 时未使用的变量

ios - 是否可以在 Objective c 中打开正在运行的后台应用程序

iphone - 切换背景图片 iphone 5 - iphone 4

ios - Xcode 命令/usr/bin/codesign 失败,退出代码 1 : errSecInternalComponent

xcode - 如何在 Xcode 中设置 Mac 应用程序的图标?

ios - 更改 tableView 中偶数单元格的背景颜色

arrays - 为什么不能在属性观察器 didSet 中更改 Swift 数组?