按下已选中的UISegmentedControl段,取消选择此段

4
如何通过再次按下同一段来取消UISegmented控件中的给定段?
例如,按下段0,它变为选定状态并保持突出显示。 再次按下段0,它将变为未选中状态并消失高亮。
该控件仅触发UIControlEventValueChanged事件。 其他事件似乎无法与其配合使用。
有一个名为“momentary”的属性,当设置为YES时,几乎允许上述行为,除了高亮仅是短暂的。 当momentary = YES时,按两次相同的段会导致两个UIControlEventValueChanged事件,但当momentary = NO时,给定段的第一次按下会导致触发UIControlEventValueChanged事件。 也就是说,对同一段进行的后续按下不会触发UIControlEventValueChanged事件。

始终会有一个段被选中,你不能取消所有的选择。最好使用UIButton创建你的段控制器。 - iphonic
我恐怕必须同意@iphonic的观点。如果您有一个好的用例来支持这种行为,请提交一个增强请求 - 这听起来确实是一件很酷的事情 - 但就目前而言,我认为您只是试图扭曲分段控件的行为,而且您不会成功的。 - matt
4个回答

10

你可以创建 UISegmentedControl 的子类:

Swift 3

class ReselectableSegmentedControl: UISegmentedControl {

    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        let previousSelectedSegmentIndex = self.selectedSegmentIndex

        super.touchesEnded(touches, withEvent: event)

        if previousSelectedSegmentIndex == self.selectedSegmentIndex {
            if let touch = touches.first {
                let touchLocation = touch.locationInView(self)
                if CGRectContainsPoint(bounds, touchLocation) {
                    self.sendActionsForControlEvents(.ValueChanged)
                }
            }
        }
    }


}

Swift 4

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    let previousSelectedSegmentIndex = self.selectedSegmentIndex

    super.touchesEnded(touches, with: event)

    if previousSelectedSegmentIndex == self.selectedSegmentIndex {
        let touch = touches.first!
        let touchLocation = touch.location(in: self)
        if bounds.contains(touchLocation) {
            self.sendActions(for: .valueChanged)
        }
    }
}

然后

 @IBAction func segmentChanged(sender: UISegmentedControl) {
    if (sender.selectedSegmentIndex == selectedSegmentIndex) {
        sender.selectedSegmentIndex =  UISegmentedControlNoSegment;
        selectedSegmentIndex = UISegmentedControlNoSegment;
    }
    else {
        selectedSegmentIndex = sender.selectedSegmentIndex;
    }
}

我尝试了半打建议,这是唯一有效的一个。 - Alper
注意:if let touch = touches.first { 这种写法过于谨慎了—— touches 数组总是包含一个或多个 UITouch 对象,因此 let touch = touches.first! 总是会成功的。除此之外,回答得非常好。干杯! - Slipp D. Thompson
1
@protspace,你能解释一下为什么我们需要检查触摸是否在视图范围内吗?既然事件首先被发送到视图,这不是理所当然的吗? - doplumi

0

虽然不完全符合您的要求,但我正在寻找类似的功能,并决定使用这个。

将doubleTap手势添加到UISegmentedControl中,以设置selectedSegmentIndex。

当您初始化UISegmentedControl时。

let doubleTap = UITapGestureRecognizer(target: self, action #selector(YourViewController.doubleTapToggle))
doubleTap.numberOfTapsRequired = 2
yourSegmentedControl.addGestureRecognizer(doubleTap)

取消选择片段的函数

@objc func doubleTapToggle () {
    yourSegmentedControl.selectedSegmentIndex = -1
    yourSegmentedControl.sendActions(for: valueChanged)
}

0

根据@protspace的答案,一种更简单的方法,无需在@IBAction中编写任何内容:

class DeselectableSegmentedControl: UISegmentedControl {
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        let previousSelectedSegmentIndex = selectedSegmentIndex

        super.touchesEnded(touches, with: event)

        if previousSelectedSegmentIndex == selectedSegmentIndex {
            let touch = touches.first!
            let touchLocation = touch.location(in: self)
            if bounds.contains(touchLocation) {
                selectedSegmentIndex = UISegmentedControl.noSegment
                sendActions(for: .valueChanged)
            }
        }
    }
}

-1

使用 Swift 可以通过 @IBOutlet weak var mySegmentedControl: UISegmentedControl!mySegmentedControl.selectedSegmentIndex = -1 对 UISegmentedControl 进行编程取消选择。至于检测片段的触摸,我不清楚。希望有人能回答这个问题。


请查看此答案这里 - adeiji

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接