2017-10-14 6 views
1

J'ai un segmentedControl 5 segment que je l'ai sous-classé en utilisant le code de cet article:UISegmentedControl décochée n'est pas reconnu dans le code même si elle est visuellement

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

pour permettre au contrôleur d'être décochée lorsque le le segment sélectionné est touché une seconde fois.

Cela fonctionne visuellement, mais lorsque vous essayez d'attribuer un UserDefault, il est simplement reconnu comme le segment qui a été touché deux fois.

Je n'arrive pas à comprendre ce que je peux ajouter au code de la sous-classe ou au code viewController pour que cela fonctionne.

Toute aide serait appréciée.

CODE Sous-classe:

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 
       } 
      } 
     } 
    } 

}

CODE viewController:

@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) 
    } 
} 
+0

ne sont pas liés, mais vous pouvez remplacer le code entier ** ** dans 'METDome_Lselect' avec une ligne:' UserDefaults.standard.set ("\ (sender.selectedSegmentIndex + 1)", forKey: key_METDome_L) ' . Le dernier 'else' ne sera jamais exécuté de toute façon. En passant, ce n'est pas Javascript ou PHP. Les noms de variable sont supposés être * camelCased * plutôt que * snake_cased *. – vadian

+0

Merci @vadian! Je savais qu'il devait y avoir un moyen de raccourcir le code, mais jamais pensé à le faire comme vous l'avez dit, ce qui est vraiment utile. Cependant, l'autre partie est le code dont j'ai vraiment besoin pour travailler. J'ai aussi essayé 'else si METDome_L.selectedSegmentIndex == UISegmentedControlNoSegment' mais je suppose que cela ne sera jamais exécuté. Sur la note des noms de variables, pour la plupart j'ai utilisé _camelCased_ Je viens d'utiliser le trait de soulignement pour séparer des parties de la variable pour la rendre plus facile à reconnaître car je suis relativement nouveau au codage et je peux facilement me perdre avec le montant de code. –

+0

Je doute que le 'IBAction' est déclenché lorsque le contrôle est désélectionné par programmation. Vous pouvez déplacer la ligne pour écrire 'NONE' dans la sous-classe – vadian

Répondre

0

Tout d'abord si vous êtes sous-classement le contrôle, vous devez utiliser ce type pour obtenir la fonctionnalité améliorée.

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

Ajouter une propriété selectionKey et enregistrer l'état UISegmentedControlNoSegment (comme Int) dans UserDefaults lorsque la commande est décochée. Un fatal error est renvoyé si la propriété est vide (elle doit être définie dans les contrôleurs de vue qui utilisent la sous-classe).

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) 
       } 
      } 
     } 
    } 
} 

Dans votre contrôleur de vue définissez la propriété selectionKey dans viewDidLoad à la touche personnalisée et enregistrer l'état sélectionné du contrôle à UserDefaults dans le IBAction. Ne fais pas de maths. Le premier segment est le segment 0 avec l'index 0. Habituez-vous aux indices basés sur le zéro. Cela rend plus pratique la restauration de l'état sélectionné.

@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) 
} 
+0

Brilliant! J'ai fait exactement ce dont j'avais besoin! La seule raison pour laquelle je sauvegardais 'userDefaults' comme _strings_ était parce que chaque segment est le numéro, et quand je le rappelle à la page suivante, il affiche le numéro. Mais comme vous le dites, il est beaucoup plus pratique de les sauvegarder en tant que valeurs _Int_ et de les convertir plus tard. –