Reputation: 2539
I'm creating a custom UIControl
subclass, and want to add a addTarget()
function, similar to UIButton. How do I do this properly? So far I have this (it works, but not sure if is a good solution):
import UIKit
class RichLabel: UIControl {
var labelTarget: Any?
var labelAction: Selector?
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func addTarget(_ target: Any?, action: Selector) {
self.labelTarget = target
self.labelAction = action
}
func buttonAction() {
if let labelTarget = labelTarget, let labelAction = labelAction {
let _ = (labelTarget as AnyObject).perform(labelAction, with: self)
}
}
The target is added from another view, like this:
var richLabel: RichLabel {
let label = RichLabel()
label.setAttributedText(title: string)
label.addTarget(self, action: #selector(richLabelAction(label:)))
return label
}
Upvotes: 2
Views: 841
Reputation: 7361
If you inherit from UIControl
, you don't need to do anything to addTarget
. Callers will use addTarget
on your custom UIControl the same way they would any other control. All your custom control has to do is decide when it wants to call those actions, and call sendActions(for:)
.
If your goal is to have this RichLabel
class function just like a button, I would add a UITapGestureRecognizer
to it, and in the gesture recognizer, call self.sendActions(for: .touchUpInside)
.
class RichLabel: UIControl {
override init(frame: CGRect) {
super.init(frame: frame)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(labelTapped))
addGestureRecognizer(tapGesture)
}
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc func labelTapped() {
// When this happens, any object that called `addTarget`
// for the .touchUpInside event will get its callback triggered
sendActions(for: .touchUpInside)
}
}
Upvotes: 3
Reputation: 5521
Since UIControl
already gives you access to func addTarget(_ target: Any?, action: Selector, for controlEvents: UIControlEvents)
you can just use that. For example, if you have the label added to a UIViewController
, and want that viewController to be able to react to something like editingDidBegin
you could add this code to your viewController:
@IBOutletWeak var richLabel: RichLabel!
override func viewDidLoad() {
super.viewDidLoad()
self.richLabel.addTarget(self, action: #selector(labelEditingDidBegin(_:)), for: UIControlEvents.editingDidBegin)
}
@objc func labelEditingDidBegin(_ sender: RichLabel) {
print(sender.text)
}
I'm not sure if your RichLabel
allows editing, etc, but you can observe whichever UIControlEvent
you need, react to that, and then execute whatever code you need in your Selector
function.
Upvotes: 3