首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Swift中,如何检测是哪个UIControlEvents触发了该动作?

在Swift中,如何检测是哪个UIControlEvents触发了该动作?
EN

Stack Overflow用户
提问于 2015-06-29 17:56:09
回答 3查看 4.9K关注 0票数 6

我现在有4个UITextField的

代码语言:javascript
复制
@IBOutlet weak var fNameTextField: UITextField!
@IBOutlet weak var lNameTextField: UITextField!
@IBOutlet weak var emailTextField: UITextField!
@IBOutlet weak var phoneTextField: UITextField!

我想要记录他们的各种事件:

代码语言:javascript
复制
[UIControlEvents.EditingChanged, UIControlEvents.EditingDidBegin, UIControlEvents.EditingDidEnd ]

但是我不希望有3个事件独立的事件处理程序,所以我创建了一个这样的函数。这个函数在告诉我哪个UITextField触发了一个事件方面做得很好,但是它没有告诉我哪个事件是触发的。

代码语言:javascript
复制
fNameTextField.addTarget(self, action: "onChangeTextField:", forControlEvents: UIControlEvents.AllTouchEvents)
lNameTextField.addTarget(self, action: "onChangeTextField:", forControlEvents: UIControlEvents.AllTouchEvents)
emailTextField.addTarget(self, action: "onChangeTextField:", forControlEvents: UIControlEvents.AllTouchEvents)
phoneTextField.addTarget(self, action: "onChangeTextField:", forControlEvents: UIControlEvents.AllTouchEvents)

func onChangeTextField(sender:UITextField){
    switch(sender){
        case fNameTextField:
            print("First Name")
        case lNameTextField:
            print("Last Name")
        case emailTextField:
            print("E-mail")
        case phoneTextField:
            print("Phone")
        default: break
    }
}

如何同时打印发送方的名称和触发事件的名称(例如:.EditingDidEnd、.EditingDidEnd、.EditingDidEnd)?

理想情况下,我不想编写多个事件处理程序,我更喜欢单个函数。

就像这样:

代码语言:javascript
复制
func onChangeTextField(sender:UITextField){
    switch(sender.eventTriggerd){
        case UIControlEvents.EditingChanged:
            println("EditingChanged")
        case UIControlEvents.EditingDidBegin:
            println("EditingDidBegin")
        case UIControlEvents.EditingDidEnd:
            println("EditingDidEnd")
        default: break
    }
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-06-29 18:20:50

不幸的是,您无法区分是什么控制事件触发了操作处理程序。这与Swift无关,它只是可可的一个特点。

这是一个奇怪的设计决策,但事实就是如此。例如,参见我的书,它抱怨它:

奇怪的是,没有一个动作选择器参数提供任何方法来了解哪个控制事件触发了当前的操作选择器调用!因此,例如,要区分Touch Up内部控制事件和Touch Up外部控制事件,它们对应的目标动作对必须指定两个不同的动作处理程序;如果将它们分派给相同的动作处理程序,则该处理程序无法发现发生了哪个控制事件。

票数 7
EN

Stack Overflow用户

发布于 2019-05-26 06:16:49

正如马特所说,这是不可能的(而且确实非常令人恼火!)我一直在用这个小帮手类来减轻我的打字负担。

每个UIControl.Event都有相应的可选Selector。您可以只设置所需的选择器,而忽略不需要的选择器。

代码语言:javascript
复制
class TargetActionMaker<T: UIControl> {

    var touchDown: Selector?
    var touchDownRepeat: Selector?
    var touchDragInside: Selector?
    var touchDragOutside: Selector?
    var touchDragEnter: Selector?
    var touchDragExit: Selector?
    var touchUpInside: Selector?
    var touchUpOutside: Selector?
    var touchCancel: Selector?
    var valueChanged: Selector?
    var primaryActionTriggered: Selector?
    var editingDidBegin: Selector?
    var editingChanged: Selector?
    var editingDidEnd: Selector?
    var editingDidEndOnExit: Selector?
    var allTouchEvents: Selector?
    var allEditingEvents: Selector?
    var applicationReserved: Selector?
    var systemReserved: Selector?
    var allEvents: Selector?

    func addActions(_ sender: T, target: Any?) {
        for selectorAndEvent in self.selectorsAndEvents() {
            if let action = selectorAndEvent.0 {
                sender.addTarget(target, action: action, for: selectorAndEvent.1)
            }
        }
    }

    private func selectorsAndEvents() -> [(Selector?, UIControl.Event)] {
        return [
            (self.touchDown, .touchDown),
            (self.touchDownRepeat, .touchDownRepeat),
            (self.touchDragInside, .touchDragInside),
            (self.touchDragOutside, .touchDragOutside),
            (self.touchDragEnter, .touchDragEnter),
            (self.touchDragExit, .touchDragExit),
            (self.touchUpInside, .touchUpInside),
            (self.touchUpOutside, .touchUpOutside),
            (self.touchCancel, .touchCancel),
            (self.valueChanged, .valueChanged),
            (self.primaryActionTriggered, .primaryActionTriggered),
            (self.editingDidBegin, .editingDidBegin),
            (self.editingChanged, .editingChanged),
            (self.editingDidEnd, .editingDidEnd),
            (self.editingDidEndOnExit, .editingDidEndOnExit),
            (self.allTouchEvents, .allTouchEvents),
            (self.allEditingEvents, .allEditingEvents),
            (self.applicationReserved, .applicationReserved),
            (self.systemReserved, .systemReserved),
            (self.allEvents, .allEvents)
        ]
    }
}

用它就像这样:

代码语言:javascript
复制
class MyControl: UIControl {

    func setupSelectors() {
        let targetActionMaker = TargetActionMaker<MyControl>()
        targetActionMaker.touchDown = #selector(self.handleTouchDown(_:))
        targetActionMaker.touchUpInside = #selector(self.handleTouchUpInside(_:))
        targetActionMaker.touchUpOutside = #selector(self.handleTouchUpOutside(_:))
        targetActionMaker.addActions(self, target: self)
    }

    @objc func handleTouchDown(_ sender: MyControl) {
        print("handleTouchDown")
    }

    @objc func handleTouchUpInside(_ sender: MyControl) {
        print("handleTouchUpInside")
    }

    @objc func handleTouchUpOutside(_ sender: MyControl) {
        print("handleTouchUpOutside")
    }
}

不过,老实说,它实际上并没有为你节省那么多的打字时间。

票数 1
EN

Stack Overflow用户

发布于 2019-05-26 15:39:51

或者,您可以使用这个小助手将UIEvent (或UITouch)转换为UIControl.Event。它的工作方式是检查触摸的Phase,在发送视图中获取其位置,并将其与前一个位置进行比较。如果您使用UIEvent,它将使用第一次触摸。

但是,请预先警告:它不能很好地处理.touchDownRepeattapCount属性的UIEvent比通常触发的.touchDownRepeat具有更长的时间持续时间。此外,它似乎在.touchDownRepeat上发送多个操作。

当然,它不处理其他UIControl.Event,如.editingDidBegin等。

代码语言:javascript
复制
public extension UIEvent {

    func firstTouchToControlEvent() -> UIControl.Event? {
            guard let touch = self.allTouches?.first else {
                print("firstTouchToControlEvent() Error: couldn't get the first touch. \(self)")
            return nil
        }
        return touch.toControlEvent()
    }

}

public extension UITouch {

    func toControlEvent() -> UIControl.Event? {
        guard let view = self.view else {
            print("UITouch.toControlEvent() Error: couldn't get the containing view. \(self)")
            return nil
        }
        let isInside = view.bounds.contains(self.location(in: view))
        let wasInside = view.bounds.contains(self.previousLocation(in: view))
        switch self.phase {
        case .began:
            if isInside {
                if self.tapCount > 1 {
                    return .touchDownRepeat
                }
                return .touchDown
            }
            print("UITouch.toControlEvent() Error: unexpected touch began outs1ide of view. \(self)")
            return nil
        case .moved:
            if isInside && wasInside {
                return .touchDragInside
            } else if isInside && !wasInside {
                return .touchDragEnter
            } else if !isInside && wasInside {
                return .touchDragExit
            } else if !isInside && !wasInside {
                return .touchDragOutside
            } else {
                print("UITouch.toControlEvent() Error: couldn't determine touch moved boundary. \(self)")
                return nil
            }
        case .ended:
            if isInside {
                return .touchUpInside
            } else {
                return.touchUpOutside
            }
        case .cancelled:
            return .touchCancel
        default:
            print("UITouch.toControlEvent() Warning: couldn't handle touch event. \(self)")
            return nil
        }
    }

}

用它就像这样:

代码语言:javascript
复制
class TestControl: UIControl {

    func setupTouchEvent() {
        self.addTarget(self, action: #selector(handleTouchEvent(_:forEvent:)), for: .allTouchEvents)
    }

    @objc func handleTouchEvent(_ sender: TestControl, forEvent event: UIEvent) {
        guard let controlEvent = event.firstTouchToControlEvent() else {
            print("Error: couldn't convert event to control event: \(event)")
            return
        }
        switch controlEvent {
        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:
            print("Error: couldn't convert event to control event, or unhandled event case: \(event)")
        }
    }
}

要实现.touchDownRepeat,您可以将该方法封装在一个小类中,并在每次触摸时节省时间,或者只需在控件中节省点击时间。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31122418

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档