【问题标题】:UIKit-Swift custom UIButton does not trigger action on tapUIKit-Swift 自定义 UIButton 不会触发点击动作
【发布时间】:2020-06-29 15:34:41
【问题描述】:

我已经定义了一个“类似 RadioButton”的 UIButton。为了实现这一点,我在 UIButton 中添加了一个子视图,我在 .touchUpInside 事件上更改了它的颜色。

问题是没有触发动作。

这是我的 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 视图的代码:

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 调试器:

有什么问题?堆栈视图与 RadioButton 具有相同的高度,并且 RadioButton 内的 stateView 具有 -1 zIndex 并且不可与用户交互。

【问题讨论】:

  • setHour() 函数被调用?
  • 不,它没有被调用
  • 检查你是否没有添加 stateView ...注释掉该代码以检查它是否因此
  • 我试过不使用 stateView,但 setHour 函数也没有被调用。
  • 你为什么用 UILabel 继承 RadioButtonLabelView .. 为什么不 UIView

标签: ios swift xcode uikit uilabel


【解决方案1】:

UIView 代替UILabel 继承RadioButtonLabelView 将解决您的问题

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

【讨论】:

    猜你喜欢
    • 2021-12-29
    • 1970-01-01
    • 2016-05-20
    • 1970-01-01
    • 2018-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多