I have a
@IBDesignable
class Fancy:UIButton
I want to
addTarget(self, action:#selector(blah),
forControlEvents: UIControlEvents.TouchUpInside)
So where in UIButton should that be done?
addTarget
?1 - I have seen layoutSubviews
suggested - is that right?
Note - experimentation shows that a problem with layoutSubviews
is that, of course, it can be called often, whenever things move around. It would be a bad idea to "addTarget" more than once.
2 - didMoveToSuperview
is another suggestion.
3 - Somewhere in (one of) the Inits?
Note - experimentation shows a fascinating problem if you do it inside Init. During Init, IBInspectable variables are not yet actually set! (So for example, I was branching depending on the "style" of control set by an IBInspectable; it plain doesn't work as @IBInspectable: won't work when running!)
4 - Somewhere else???
I tried to do it in Init, and it worked well. But it breaks designables from working in the Editor.
By thrashing around, I came up with this (for some reason both must be included?)
@IBDesignable
class DotButton:UIButton
{
@IBInspectable var mainColor ... etc.
required init?(coder decoder: NSCoder)
{
super.init(coder: decoder)
addTarget(self, action:#selector(blah),
forControlEvents: UIControlEvents.TouchUpInside)
}
override init(frame:CGRect)
{
super.init(frame:frame)
}
I don't know why that works, and I don't understand why there would be two different init routines.
What's the correct way to include addTarget
in a UIButton?
override func endTrackingWithTouch(touch: UITouch?, withEvent event: UIEvent?) {
super.endTrackingWithTouch(touch, withEvent: event)
if let touchNotNil = touch {
if self.pointInside(touchNotNil.locationInView(self), withEvent: event) {
print("it works")
}
}
}
addTarget
addTarget
method is part of action-target interface which is considered 'public'. Anything with reference to your button can, say, remove all of its actions, effectively breaking it. It is preffered to use some of 'protected' means, for instance endTrackingWithTouch
which is accessible only to be overriden, not called directly. This way it will not interfere with any external objects using action-target mechanism.
(I know there is no strict 'public' or 'protected' in ObjC/UIKit, but the concept remains)
If you want to do it exactly your way then your example is all good, just copy addTarget
call to init(frame:CGRect)
.
Or you can put addTarget
in awakeFromNib
(don't forget super) instead of init?(coder decoder: NSCoder)
, but you will be forced to implement init with coder anyway, so...
layoutSubviews
and didMoveToSuperView
both are terrible ideas. Both may happen more than once resulting in blah
target-action added again. Then blah
will be called multiple times for a single click.
By the Cocoa MVC (which is enforced by UIKit classes implmentation) you should assign that action to the object controlling that button, animations or not. Most often that object will be Cocoa MVC 'Controller' - UIViewController
.
If you create button programmatically UIViewController
should assign target to itself in overridden loadView
or viewDidLoad
. When button is loaded from nib the preffered way is to assign target action in xib itself.
As mentioned here in real MVC views do not send actions to themselves. The closest thing to real MVC Controller in UIKit is UIGestureRecognizer
.
Be warned that it's pretty difficult to pull of real MVC with UIKit class set.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With