如何以编程方式触发 `UISwitch` 的操作?

huangapple go评论106阅读模式
英文:

How to programmatically invoke the action of a `UISwitch`?

问题

我有一个UIViewController,位于一个SPM包中,其中包含一个带有一些简单单元格的UITableView - 这些单元格要么是详细披露,要么有一个UISwitch

我正在尝试编写单元测试,以确认当特定行中的开关被切换时,会调用所需的操作。该操作是由其他代码提供的,因此单元格配置如下:

let toggle = UISwitch(frame: .zero, primaryAction: UIAction(handler: { action in
    guard let toggle = action.sender as? UISwitch else { return }
    toggleAction(toggle.isOn)
}))
cell.accessoryView = toggle

(其中toggleAction是传递给VC的init的众多操作之一)

我的测试可以找到感兴趣的行以及其中的开关。它可以通过.isOn修改值,但这不会触发操作。我知道需要一个UIApplication才能使.sendActions(for:)起作用,因此我使用了这里的解决方案,并确认它对UIButton有效。我尝试发送各种事件给UISwitch.touchUpInside.valueChanged.primaryActionTriggered),但它们都不会导致注册的操作被调用。这是否可能?

英文:

I have a UIViewController, in an SPM package, with a UITableView with some simple cells - they're either detail disclosures or have a UISwitch.

I'm trying to write unit tests to confirm that when the switch in a specific row is toggled, the desired action is invoked. That action was provided by other code, so the cell configuration looks like:

let toggle = UISwitch(frame: .zero, primaryAction: UIAction(handler: { action in
    guard let toggle = action.sender as? UISwitch else { return }
    toggleAction(toggle.isOn)
}))
cell.accessoryView = toggle

(where toggleAction was one of many passed to the VC's init)

My test can find the row of interest, and the switch on it. It can modify the value via .isOn, but that doesn't trigger the action. I am aware of the need for a UIApplication in order for .sendActions(for:) to work, so am using the solution here, and confirm that it works for UIButtons. I have tried sending various events to the UISwitch (.touchUpInside, .valueChanged, .primaryActionTriggered), but none of them cause the registered action to be invoked. Is it possible?

答案1

得分: 1

UISwitch 是一个 UIControl。由于你使用了一个 UIAction 来设置开关的主要动作,你可以在开关上调用 sendActions

let switch = ... // 从表格单元格获取 UISwitch 的引用
switch.isOn = true // 根据需要设置为 true 或 false
switch.sendActions(for: .primaryActionTriggered)

这将导致调用开关的动作,进而调用你的 toggleAction 方法。

这不需要引用 UIApplication

英文:

UISwitch is a UIControl. Since you setup the switch with a UIAction for the primary action, you can call sendActions on the switch:

let switch = ... // a reference to the UISwitch from the table cell
switch.isOn = true // or false as needed
switch.sendActions(for: .primaryActionTriggered)

This will result in the switch's action being called which in turn calls your toggleAction method.

No reference to the UIApplication is needed for this.


Here is some sample code that demonstrates that using sendActions works for both UISwitch and UIButton and that it works whether the control is setup with a primary action or with a target/selector.

The following can be run in an iOS Swift Playground.

class Controls {
    func toggleAction(_ isOn: Bool) {
        print("toggleAction: \(isOn)")
    }
    @objc func toggleHandler(_ sender: UIControl) {
        print("toggleHandler: \(sender)")
    }

    lazy var toggle = UISwitch(frame: .zero, primaryAction: UIAction(handler: { action in
        guard let toggle = action.sender as? UISwitch else { return }
        self.toggleAction(toggle.isOn)
    }))
    lazy var button = UIButton(primaryAction: UIAction(handler: { action in
        self.toggleAction(false)
    }))
    lazy var other = UIButton(type: .custom)

    func doStuff() {
        other.addTarget(self, action: #selector(toggleHandler), for: .touchUpInside)
        toggle.isOn.toggle()
        toggle.sendActions(for: .primaryActionTriggered)
        other.sendActions(for: .touchUpInside)
        button.sendActions(for: .primaryActionTriggered)
    }
}

let x = Controls()
x.doStuff()

The output will be something like:

>toggleAction: true
toggleHandler: <UIButton: 0x7fb77f406320; frame = (0 0; 0 0); opaque = NO; layer = <CALayer: 0x6000037e2fc0>>
toggleAction: false

huangapple
  • 本文由 发表于 2023年8月4日 22:54:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76837047.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定