【问题标题】:UISegmentedControl deselected is not recognised in code although it is visuallyUISegmentedControl 取消选择在代码中无法识别,尽管它是可视的
【发布时间】:2017-10-14 23:34:57
【问题描述】:

我有一个 5 段 segmentedControl,我使用这篇文章中的代码对其进行了子类化:

How to deselect a segment in Segmented control button permanently till its clicked again

允许在第二次触摸所选段时取消选择控制器。

这在视觉上有效,但在尝试分配 UserDefault 时,它只是被识别为被触摸两次的片段。

我不知道我可以在子类代码或 viewController 代码中添加什么来完成这项工作。

任何帮助将不胜感激。

子类代码:

class mySegmentedControl: UISegmentedControl {
    @IBInspectable var allowReselection: Bool = true

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        let previousSelectedSegmentIndex = self.selectedSegmentIndex
        super.touchesEnded(touches, with: event)
        if allowReselection && previousSelectedSegmentIndex == self.selectedSegmentIndex {
            if let touch = touches.first {
                let touchLocation = touch.location(in: self)

                if bounds.contains(touchLocation) {
                    self.sendActions(for: .valueChanged)
                    self.selectedSegmentIndex = UISegmentedControlNoSegment
                }
            }
        }
    }

}

查看控制器代码:

@IBOutlet weak var METDome_L: UISegmentedControl!
let key_METDome_L = "METDome_L"
var METD_L: String!

@IBAction func METDome_Lselect(_ sender: Any) {
    if METDome_L.selectedSegmentIndex == 0{
        METD_L = "1"
        UserDefaults.standard.set(METD_L, forKey: key_METDome_L)
    }
    else if METDome_L.selectedSegmentIndex == 1{
        METD_L = "2"
        UserDefaults.standard.set(METD_L, forKey: key_METDome_L)
    }
    else if METDome_L.selectedSegmentIndex == 2{
        METD_L = "3"
        UserDefaults.standard.set(METD_L, forKey: key_METDome_L)
    }
    else if METDome_L.selectedSegmentIndex == 3{
        METD_L = "4"
        UserDefaults.standard.set(METD_L, forKey: key_METDome_L)
    }
    else if METDome_L.selectedSegmentIndex == 4{
        METD_L = "5"
        UserDefaults.standard.set(METD_L, forKey: key_METDome_L)
    }
    else{
        METD_L = "NONE"
        UserDefaults.standard.set(METD_L, forKey: key_METDome_L)
    }
}

【问题讨论】:

  • 不相关,但您可以将METDome_Lselect 中的整个 代码替换为一行:UserDefaults.standard.set("\(sender.selectedSegmentIndex + 1)", forKey: key_METDome_L)。最后一个else 无论如何都不会被执行。顺便说一句,这不是 Javascript 或 PHP。变量名应该是 camelCased 而不是 snake_cased
  • 谢谢@vadian!我知道必须有一种方法来缩短代码,但从来没有想过按照你说的方式去做,所以这真的很有帮助。然而,其他部分是我真正需要开始工作的代码。我也试过else if METDome_L.selectedSegmentIndex == UISegmentedControlNoSegment 但我想这也永远不会被执行。关于变量名称的注释,在大多数情况下,我使用 camelCased 我只是使用下划线来分隔变量的各个部分,以便更容易识别,因为我对编码还很陌生,我可以很容易被大量的代码迷失。
  • 我怀疑以编程方式取消选择控件时会触发IBAction。您可以移动该行以将NONE 写入子类
  • @vadian 我曾想过,但我在多个分段控件上使用它,因此如果我尝试这样做,它们将开始相互影响。除非我为每个分段控件创建一个子类,但这似乎效率极低。我还检查了第二次点击时发生的情况,它看起来像是以编程方式第二次设置了它被点击的选择。
  • 向子类添加属性selectionKey(或任何合适的)并为每个实例单独设置。而不是使用String,我会写IntUserDefaults 而不做数学。段1(实际上是段0)是索引0(几乎所有编程语言都使用从零开始的索引),UISegmentedControlNoSegment 无论如何都代表-1。这使得恢复值变得非常容易。

标签: ios swift xcode nsuserdefaults uisegmentedcontrol


【解决方案1】:

首先,如果您要对控件进行子类化,则必须使用该类型来获得增强的功能。

@IBOutlet weak var METDome_L: MySegmentedControl! // class names start with a capital letter

添加属性selectionKey,并在取消选择控件时将状态UISegmentedControlNoSegment(为Int)保存在UserDefaults中。如果属性为空(必须在使用子类的视图控制器中设置),则抛出 fatal error

class MySegmentedControl: UISegmentedControl {
    @IBInspectable var allowReselection: Bool = true

    var selectionKey = ""

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        let previousSelectedSegmentIndex = self.selectedSegmentIndex
        super.touchesEnded(touches, with: event)
        if allowReselection && previousSelectedSegmentIndex == self.selectedSegmentIndex {
            if let touch = touches.first {
                let touchLocation = touch.location(in: self)

                if bounds.contains(touchLocation) {
                    self.sendActions(for: .valueChanged)
                    self.selectedSegmentIndex = UISegmentedControlNoSegment
                    guard !selectionKey.isEmpty else { fatalError("selectionKey must not be empty")
                    UserDefaults.standard.set(UISegmentedControlNoSegment, forKey: selectionKey)
                }
            }
        }
    }
}

在您的视图控制器中,将viewDidLoad 中的属性selectionKey 设置为自定义键,并将控件的选定状态保存到IBAction 中的UserDefaults。不要任何数学。第一个段是段 0,索引为 0。习惯于从零开始的索引。这样可以更方便地恢复选中状态。

@IBOutlet weak var METDome_L: MySegmentedControl!
let key_METDome_L = "METDome_L"

override func viewDidLoad()
{
    super.viewDidLoad()
    METDome_L.selectionKey = key_METDome_L
}

@IBAction func METDome_Lselect(_ sender: UISegmentedControl) {
    UserDefaults.standard.set(sender.selectedSegmentIndex, forKey: key_METDome_L)
}

【讨论】:

  • 太棒了!正是我需要的!我将userDefaults 保存为 strings 的唯一原因是因为每个段都是数字,当我在下一页调用它时,它会显示数字。但是正如您所说,将它们保存为 Int 值并在以后转换它们要方便得多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-10
  • 1970-01-01
  • 2016-02-01
  • 1970-01-01
相关资源
最近更新 更多