Swift以编程方式为带闭合的按钮创建函数 [英] Swift programmatically create function for button with a closure
问题描述
在Swift中,您可以为按钮创建一个函数,如下所示:
In Swift you can create a function for a button like this:
button.addTarget(self, action: #selector(buttonAction), forControlEvents: .TouchUpInside)
但是有一种方法可以执行以下操作:
However is there a way I can do something like this:
button.whenButtonIsClicked({Insert code here})
这样,我什至没有为按钮声明显式函数。我知道我可以使用按钮标签,但我希望改为使用按钮标签。
That way I do not even have too declare an explicit function for the button. I know I can use button tags but I would prefer to do this instead.
推荐答案
创建自己的 UIButton
子类来做到这一点:
Create your own UIButton
subclass to do this:
class MyButton: UIButton {
var action: (() -> Void)?
func whenButtonIsClicked(action: @escaping () -> Void) {
self.action = action
self.addTarget(self, action: #selector(MyButton.clicked), for: .touchUpInside)
}
// Button Event Handler:
// I have not marked this as @IBAction because it is not intended to
// be hooked up to Interface Builder
@objc func clicked() {
action?()
}
}
在创建按钮时用 UIButton
代替 MyButton
以编程方式,然后调用 whenButtonIsClicked
设置其功能。
Substitute MyButton
for UIButton
when you create buttons programmatically and then call whenButtonIsClicked
to set up its functionality.
您也可以将其与 UIButton
(只需将其类更改为 MyButton
),然后调用 whenButtonIsClicked
在 viewDidLoad
中。
You can also use this with UIButton
s in a Storyboard (just change their class to MyButton
) and then call whenButtonIsClicked
in viewDidLoad
.
@IBOutlet weak var theButton: MyButton!
var count = 0
override func viewDidLoad() {
super.viewDidLoad()
// be sure to declare [unowned self] if you access
// properties or methods of the class so that you
// don't create a strong reference cycle
theButton.whenButtonIsClicked { [unowned self] in
self.count += 1
print("count = \(self.count)")
}
功能更强大的实现
事实上,程序员可能想要处理的事件不仅仅是 .touchUpInside
,我写了这个功能更强大的版本,它支持每个 UIButton $ c $多次关闭c>和每个事件类型的多个闭包。
Recognizing the fact that programmers might want to handle more events than just .touchUpInside
, I wrote this more capable version which supports multiple closures per UIButton
and multiple closures per event type.
class ClosureButton: UIButton {
private var actions = [UInt : [((UIControl.Event) -> Void)]]()
private let funcDict: [UInt : Selector] = [
UIControl.Event.touchCancel.rawValue: #selector(eventTouchCancel),
UIControl.Event.touchDown.rawValue: #selector(eventTouchDown),
UIControl.Event.touchDownRepeat.rawValue: #selector(eventTouchDownRepeat),
UIControl.Event.touchUpInside.rawValue: #selector(eventTouchUpInside),
UIControl.Event.touchUpOutside.rawValue: #selector(eventTouchUpOutside),
UIControl.Event.touchDragEnter.rawValue: #selector(eventTouchDragEnter),
UIControl.Event.touchDragExit.rawValue: #selector(eventTouchDragExit),
UIControl.Event.touchDragInside.rawValue: #selector(eventTouchDragInside),
UIControl.Event.touchDragOutside.rawValue: #selector(eventTouchDragOutside)
]
func handle(events: [UIControl.Event], action: @escaping (UIControl.Event) -> Void) {
for event in events {
if var closures = actions[event.rawValue] {
closures.append(action)
actions[event.rawValue] = closures
} else {
guard let sel = funcDict[event.rawValue] else { continue }
self.addTarget(self, action: sel, for: event)
actions[event.rawValue] = [action]
}
}
}
private func callActions(for event: UIControl.Event) {
guard let actions = actions[event.rawValue] else { return }
for action in actions {
action(event)
}
}
@objc private func eventTouchCancel() { callActions(for: .touchCancel) }
@objc private func eventTouchDown() { callActions(for: .touchDown) }
@objc private func eventTouchDownRepeat() { callActions(for: .touchDownRepeat) }
@objc private func eventTouchUpInside() { callActions(for: .touchUpInside) }
@objc private func eventTouchUpOutside() { callActions(for: .touchUpOutside) }
@objc private func eventTouchDragEnter() { callActions(for: .touchDragEnter) }
@objc private func eventTouchDragExit() { callActions(for: .touchDragExit) }
@objc private func eventTouchDragInside() { callActions(for: .touchDragInside) }
@objc private func eventTouchDragOutside() { callActions(for: .touchDragOutside) }
}
演示
class ViewController: UIViewController {
var count = 0
override func viewDidLoad() {
super.viewDidLoad()
let button = ClosureButton(frame: CGRect(x: 50, y: 100, width: 60, height: 40))
button.setTitle("press me", for: .normal)
button.setTitleColor(.blue, for: .normal)
// Demonstration of handling a single UIControl.Event type.
// If your closure accesses self, be sure to declare [unowned self]
// to prevent a strong reference cycle
button.handle(events: [.touchUpInside]) { [unowned self] _ in
self.count += 1
print("count = \(self.count)")
}
// Define a second handler for touchUpInside:
button.handle(events: [.touchUpInside]) { _ in
print("I'll be called on touchUpInside too")
}
let manyEvents: [UIControl.Event] = [.touchCancel, .touchUpInside, .touchDown, .touchDownRepeat, .touchUpOutside, .touchDragEnter,
.touchDragExit, .touchDragInside, .touchDragOutside]
// Demonstration of handling multiple events
button.handle(events: manyEvents) { event in
switch event {
case .touchCancel:
print("touchCancel")
case .touchDown:
print("touchDown")
case .touchDownRepeat:
print("touchDownRepeat")
case .touchUpInside:
print("touchUpInside")
case .touchUpOutside:
print("touchUpOutside")
case .touchDragEnter:
print("touchDragEnter")
case .touchDragExit:
print("touchDragExit")
case .touchDragInside:
print("touchDragInside")
case .touchDragOutside:
print("touchDragOutside")
default:
break
}
}
self.view.addSubview(button)
}
}
这篇关于Swift以编程方式为带闭合的按钮创建函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!