iOS:在 Swift 中重新创建 addTarget() 的最佳实践?
Posted
技术标签:
【中文标题】iOS:在 Swift 中重新创建 addTarget() 的最佳实践?【英文标题】:iOS: Best practice for recreating addTarget() in Swift? 【发布时间】:2018-01-18 18:55:21 【问题描述】:我正在创建一个自定义UIControl
子类,并想添加一个addTarget()
函数,类似于UIButton。我该如何正确地做到这一点?到目前为止,我有这个(它有效,但不确定是否是一个好的解决方案):
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)
目标是从另一个视图添加的,如下所示:
var richLabel: RichLabel
let label = RichLabel()
label.setAttributedText(title: string)
label.addTarget(self, action: #selector(richLabelAction(label:)))
return label
【问题讨论】:
UIControl
已经有func addTarget(_ target: Any?, action: Selector, for controlEvents: UIControlEvents)
可用 - 为什么不直接使用它呢?您只需选择与触发Selector
所需的操作相匹配的UIControlEvent
。
所以我应该重写那个函数?或者如何触发使用包含的 UIControl addTarget 函数设置的选择器?
这完全取决于目标是谁。这是RichLabel
在用户与之交互时会做出反应并做某事的事情,还是包含UIViewController
需要知道的事情?
目标是另一个视图或其他什么。它应该像通常使用的 UIButton 的 addTarget 一样使用。更新了我的问题。
检查我的答案 - 这将完成我认为你所要求的。与我处理按钮点击的方式完全相同。
【参考方案1】:
如果您从UIControl
继承,则无需对addTarget
执行任何操作。调用者将在您的自定义 UIControl 上使用addTarget
,就像使用任何其他控件一样。您的自定义控件所要做的就是决定何时调用这些操作,然后调用sendActions(for:)
。
如果您的目标是让这个RichLabel
类函数像一个按钮一样,我会在其中添加一个UITapGestureRecognizer
,然后在手势识别器中调用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)
【讨论】:
谢谢。这就是我一直在寻找的。 :) 我可能需要为许多不同的事件添加目标,所以我可能需要做一个自定义的,所以我可以拥有与UIControlState
提供的不同/更多的状态。你知道我应该如何最好地存储目标/选择器吗? UIControl 如何在内部做到这一点?
存储动作/选择器是UIControl
的一个实现细节,我认为我们作为开发人员不需要了解。您确定不能使用UIControlState
提供的值吗?请记住,您可以在选择器调用的函数中传回RichLabel
。所以如果你有一个#selector(labelTapped(_:))
,你的函数看起来像func labelTapped(_ label: RichLabel)
。因此,您可以使用label
来获取有关上下文的更多信息,而不是一堆不同的选择器。
好的,谢谢。我会尝试通过这种方式解决它。 :)
这不是真的:“您的自定义控件所要做的就是决定何时要调用这些操作..”。这不是必需的,我会说这是一种不好的做法。将 TapGR 添加到 UIControl 类是不必要的,并且从那里发送操作会令人困惑。谁会期望 UIControl 的 TouchUpInside 事件会立即被调用?没有机会取消触摸(通过 TouchUpOutside)等。【参考方案2】:
由于UIControl
已经允许您访问func addTarget(_ target: Any?, action: Selector, for controlEvents: UIControlEvents)
,您可以使用它。例如,如果您将标签添加到 UIViewController
,并希望该 viewController 能够对 editingDidBegin
之类的内容做出反应,您可以将此代码添加到您的 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)
我不确定您的RichLabel
是否允许编辑等,但您可以观察您需要的任何UIControlEvent
,对其做出反应,然后在您的Selector
函数中执行您需要的任何代码。
【讨论】:
@Connor 啊,好的,我从问题中不明白这一点。不错 - 你得到了我的支持。以上是关于iOS:在 Swift 中重新创建 addTarget() 的最佳实践?的主要内容,如果未能解决你的问题,请参考以下文章
重新加载uitableviewcell,iOs / Swift时随机滚动
为啥网络库无法检测到何时在 Swift Ios 中重新连接了互联网
wkwebview ios 10在重新创建webview后停止使用localfileurl加载文件