我有一个
@IBDesignable
class Fancy:UIButton
我想
addTarget(self, action:#selector(blah),
forControlEvents: UIControlEvents.TouchUpInside)
那么UIButton应该在哪里完成?
addTarget
的最佳位置在哪里? 1 - 我看到layoutSubviews
建议 - 是吗?
注意 - 实验表明layoutSubviews
的一个问题是,当事情四处移动时,它可以经常被调用。 " addTarget"是一个坏主意。不止一次。
2 - didMoveToSuperview
是另一个建议。
3 - Inits中的某个地方?
注意 - 如果你在Init中进行实验,那么实验会显示一个引人入胜的问题。在Init期间,IBInspectable变量尚未实际设置! (例如,我的分支取决于IBInspectable设置的"样式和#34;它显然不起作用@IBInspectable:在运行时不会工作!)
4 - 其他地方???
我试图在Init中做到这一点,并且效果很好。但它打破了编辑工作中的可设计性。
通过晃来晃去,我想出了这个(出于某种原因,两者都必须被包括在内?)
@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)
}
我不知道为什么会有效,而且我不明白为什么会有两种不同的初始化例程。
在UIButton中包含addTarget
的正确方法是什么?
答案 0 :(得分:3)
您不应将生成动作的同一对象添加为目标
目标及其回调应该是另一个对象,通常是视图控制器
有2个inits方法,因为可以通过调用init或来自nib / xib的deserializion(NSCoder
)进程来实例化按钮。由于您可能已将按钮添加到故事板,因此调用的init方法为init?(_: NSCoder)
。
的 [UPDATE] 强>
我同意你在评论中所说的内容,但我认为动作目标模式应该用于与其他对象进行通信,我使用条件,因为据我所知,我从未见过像你在Apple中写的那样代码或其他一些库。如果你想拦截并在按钮内部做一些动作,你应该覆盖UIControl
中公开的一些方法。
关于可设计,你再次是正确的。如果您以编程方式创建按钮,则会调用init(frame)
,如果按钮来自xib,则会调用init(coder)
。
在可设计的过程中也调用方法init(frame)
。在这一点上,我认为最好的选择是直接调试你的观点。
现在你应该能够理解问题所在。
答案 1 :(得分:3)
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
方法是动作目标界面的一部分,被视为' public '。任何参考你的按钮的东西都可以说是remove all of its actions,有效地打破它。它优先使用一些 受保护的'意味着,例如endTrackingWithTouch
只能被overriden访问,而不是直接调用。这样它就不会使用动作目标机制干扰任何外部对象。
(我知道在ObjC / UIKit中没有严格的公共'或#39;保护'但概念仍然存在)
如果您想完全按自己的方式行事,那么您的示例一切都很好,只需将addTarget
电话复制到init(frame:CGRect)
即可。
或者您可以将addTarget
放入awakeFromNib
(不要忘记超级)而不是init?(coder decoder: NSCoder)
,但无论如何您将被迫使用编码器实现init,所以..
layoutSubviews
和didMoveToSuperView
都是糟糕的想法。两者都可能不止一次发生,导致再次添加blah
目标操作。然后,只需单击一次即可多次调用blah
。
通过Cocoa MVC(由UIKit类实施强制执行),您应该将该操作分配给控制该按钮的对象,动画与否。大多数情况下,该对象将是 Cocoa MVC ' Controller' - UIViewController
。
如果您以编程方式创建按钮UIViewController
,则应在覆盖的loadView
或viewDidLoad
中将目标指定给自己。当从nib加载按钮时,优先的方法是在xib本身中分配目标动作。
如上所述真实MVC 视图中的here不会向自己发送动作。与UIKit中真实MVC 控制器最接近的是UIGestureRecognizer
。
请注意,使用UIKit类集设置真实MVC 非常困难。
答案 2 :(得分:2)
您的初始化方法不正确,这将有效:
```swift
override init(frame: CGRect) {
super.init(frame: frame)
self.loadNib()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.loadNib()
}
private func loadNib() {
let nibView = NSBundle(forClass: self.classForCoder).loadNibNamed("yourView", owner: self, options: nil).first as! UIView
nibView.frame = self.bounds
nibView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
self.button.addTarget(self, action: #selector(action), forControlEvents: .TouchUpInside)
self.addSubview(nibView)
}
```
答案 3 :(得分:2)
如何实施awakeFromNib
并在那里实施?
当您在Interface Builder的上下文中运行代码时,您还可以有条件地运行(或不运行)代码:
#if !TARGET_INTERFACE_BUILDER
// this code will run in the app itself
#else
// this code will execute only in IB
#endif