Обычный класс Swift не может получать сенсорные события от UIButton - PullRequest
0 голосов
/ 01 декабря 2018

Я пытаюсь создать отдельный класс для группы кнопок, чтобы обрабатывать логику только одной кнопки, выбранной за один раз (переключатель)

Логика здесь не важна.Я просто не могу получить событие touchUpIndside при нажатии на одну из этих кнопок.

Я установил для себя цель (собственный класс RadionButtonsController), но этот класс не может получить событие.

Я пыталсядобавить UIResponder в качестве суперкласса.Но все еще не могу получить событие в этом классе.

Вот мой код:

import UIKit

class RadioButtonsController: UIResponder
{
    var buttons = [UIButton]()
    var selectedValue: String?

    init(numberOfButtons: Int, titles: [String], values: [String])
    {
        guard titles.count == numberOfButtons && values.count == numberOfButtons else
        {
            fatalError("number of items in `titles` and `values` must equal to the `numberOfButtons`")
        }

        super.init()

        for i in 0..<numberOfButtons
        {
            let button = UIButton(type: .system)
            button.setTitle(titles[i], for: .normal)
            button.backgroundColor = [UIColor.red, UIColor.blue, UIColor.gray, UIColor.yellow].randomElement()
            button.addTarget(self, action: #selector(radioButtonSelected(sender:)), for: .touchUpInside)
            buttons.append(button)
        }
    }

    @objc private func radioButtonSelected(sender: UIButton)
    {   
        print("Selected Button: \(sender)") // this is will never get printed
    }


}

И я использую этот контроллер кнопок в ячейке табличного представления.В cellForRowAtIndexPath:

let itemOptionsCell = tableView.dequeueReusableCell(withIdentifier: "ItemOptionsCell", for: indexPath) as! ItemOptionsTableViewCell
let itemOption = logicController.item.options[indexPath.row]
itemOptionsCell.optionsTitleLabel.text = itemOption.name

let radioButtonsController = RadioButtonsController(numberOfButtons: itemOption.values.count,
                                                             titles: itemOption.values.map({ $0.name }),
                                                             values: itemOption.values.map({ $0.valueID }))
for button in radioButtonsController.buttons
{
    itemOptionsCell.buttonsStackView.addArrangedSubview(button)
}

return itemOptionsCell

Кнопки кажутся нажатыми, но метод radionButtonSelected(snder:) никогда не вызывается.

Ответы [ 2 ]

0 голосов
/ 01 декабря 2018

Проблема в том, что ваш код создает объект RadioButtonsController, а затем выбрасывает его.Таким образом, вашим кнопкам некому отправлять свои действия.

0 голосов
/ 01 декабря 2018

Если вы хотите создать RadioButton без использования каких-либо внешних модулей, вы можете использовать этот код:

import Foundation
import UIKit
class HRadioButton: UIButton {
    @IBOutlet var otherButtons: [HRadioButton]!
    var hSelected = false {
        didSet {
            if hSelected {
                if imageView != nil{
                     self.setImage(checkedImage, for: .normal)
                }else{
                    self.setImage(checkedImage, for: .normal)
                    print("image null")
                }
                if self.otherButtons != nil {
                    for button in self.otherButtons {
                        button.hSelected = false
                        button.imageView?.image = self.unCheckedImage
                    }
                } else {
                    print("Button is null ")
                }
            }
        }
    }
    var checkedImage: UIImage!, unCheckedImage: UIImage!

    override func awakeFromNib() {
        super.awakeFromNib()
        checkedImage = #imageLiteral(resourceName: "ic_radio_button_checked").maskWithColor(color: tintColor)
        unCheckedImage = #imageLiteral(resourceName: "ic_radio_button_unchecked").maskWithColor(color: tintColor)
        setImage(unCheckedImage, for: .normal)
        alignImageRight()

        self.onTap {
             self.imageView?.image = self.checkedImage
            self.hSelected = true
            if self.otherButtons != nil {
                for button in self.otherButtons {
                    button.hSelected = false
                    button.imageView?.image = self.unCheckedImage
                }
            } 

        }
    }
}




extension UIImage {

    func maskWithColor(color: UIColor) -> UIImage? {
        let maskImage = cgImage!

        let width = size.width
        let height = size.height
        let bounds = CGRect(x: 0, y: 0, width: width, height: height)

        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
        let context = CGContext(data: nil, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)!

        context.clip(to: bounds, mask: maskImage)
        context.setFillColor(color.cgColor)
        context.fill(bounds)

        if let cgImage = context.makeImage() {
            let coloredImage = UIImage(cgImage: cgImage)
            return coloredImage
        } else {
            return nil
        }
    }

}



extension UIView {

    // In order to create computed properties for extensions, we need a key to
    // store and access the stored property
    fileprivate struct AssociatedObjectKeys {
        static var tapGestureRecognizer = "MediaViewerAssociatedObjectKey_mediaViewer"
    }

    fileprivate typealias Action = (() -> Void)?

    // Set our computed property type to a closure
    fileprivate var tapGestureRecognizerAction: Action? {
        set {
            if let newValue = newValue {
                // Computed properties get stored as associated objects
                objc_setAssociatedObject(self, &AssociatedObjectKeys.tapGestureRecognizer, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
            }
        }
        get {
            let tapGestureRecognizerActionInstance = objc_getAssociatedObject(self, &AssociatedObjectKeys.tapGestureRecognizer) as? Action
            return tapGestureRecognizerActionInstance
        }
    }

    // This is the meat of the sauce, here we create the tap gesture recognizer and
    // store the closure the user passed to us in the associated object we declared above
    public func onTap(action: (() -> Void)?) {
        self.isUserInteractionEnabled = true
        self.tapGestureRecognizerAction = action
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture))
        self.addGestureRecognizer(tapGestureRecognizer)
    }

    // Every time the user taps on the UIImageView, this function gets called,
    // which triggers the closure we stored
    @objc fileprivate func handleTapGesture(sender: UITapGestureRecognizer) {
        if let action = self.tapGestureRecognizerAction {
            action?()
        } else {
            print("no action")
        }
    }

}

из xcode storyboard ui назначьте класс HRadioButton в качестве класса Button, тогда вы найдете другиеButtons вИнспектор подключений изображение значка Инспектора подключений в Xcode

в xcode вы найдете другие кнопки Появитесь там, поэтому перетащите его на другие кнопки

и повторите этот процесс на всех кнопкахВы хотите сделать его как Radio Group, например, у меня есть кнопка A, кнопка B, кнопка C. Я назначу класс кнопке A, затем перетащу другие кнопки из Инспектора подключений на кнопки B и C, затем назначу кнопку Class To B и заставлю другие кнопки ссылатьсяк кнопкам A, C и т. д.

Позже вы можете получить выбранный Btn из свойства hSelected

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...