UIPickerView et renvoi

Bonjour à tous, un peu moins débutant, j’essaie de m’engager sur ma propre application. Ma question du jour, concerne le UIPickerView:

  1. comment faire, à partir du UIPickerView pour enregistrer le choix de ce dernier, et où est-ce que le choix est enregistré ?
  2. une fois le choix fait, comment rediriger vers une page cible ?
    Merci d’avance pour vos lumières.

Bonjour Didier,

UIPickerView fonctionne comme une tableView / CollectionView.

Avec le protocole UIPickerViewDelegate tu peux récupérer la ligne sélectionnée:

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {}

Seb.

L’utilisation du PickerView est nettement plus compliqué que cela ne devrait être. Encore un survivant des vieilles API d’Apple de la préhistoire.

Pour l’utiliser il faut déclarer le viewControler comme étant la DataSource et le délégué (Delegate) du picker. Je t’ai tapé un petit exemple :

import UIKit

// Contenu du PickerView
fileprivate let listeDesFruits = [
    "Pomme",
    "Cerise",
    "Ananas",
    "Kiwi",
    "Banane"]

class ViewController:   UIViewController,
                        UIPickerViewDelegate,
                        UIPickerViewDataSource {

    @IBOutlet weak var pickerView: UIPickerView!
    @IBOutlet weak var label: UILabel!
    
    // Initialisation viewController
    override func viewDidLoad() {
        super.viewDidLoad()
        pickerView.dataSource = self
        pickerView.delegate = self
    }
    
    // ---------
    // MARK : Remplissage du PickView
    // Une seule colonne (cas le plus fréquent)
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    
    // Nombre de lignes
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return listeDesFruits.count
    }
    
    // Remplissage de chaque ligne
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return listeDesFruits[row]
    }


    // -------------
    // Delegate du Picker View
    
    // Cette méthode est appelée APRES la sélection d'un élément du Picker
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        // Lecture élément
        let selection = listeDesFruits[row]
        // Affichage dans la fenêtre Xcode
        print ("--")
        print ("ligne : ", row)
        print ("colonne : ", component)
        print ("Fruit : ", selection)
        // Affichage sur l'écran avec un Label
        label.text = selection
        label.sizeToFit()
    }
    

}

Lorsque le doigt de l’utilisateur relâche le pickView, il appelle automatiquement la méthode suivante en lui passant les paramètres de sélection :

row : ligne sélectionnée
component : colonne sélectionnée

Il suffit de lire le tableau contenant la structure du pickerView pour connaître la valeur sélectionnée.

    // Cette méthode est appelée APRES la sélection d'un élément du Picker
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        // Lecture élément
        let selection = listeDesFruits[row]
        // Faire quelque chose avec la sélection
        // .......
    }

Merci pour vos réponses, çà fonctionne pour un UIPickerView et un component ou wheel.
Mais comment le faire si j’intègre 3 wheels dans le même UIPickerView et que selon les choix pour chaque wheel, çà dirige vers un nouveau ViewController, donc une nouvelle page ?
Merci d’avance … :slight_smile:

Petite démo avec un viewPicker à deux composants (fruit/couleur). L’application mémorise les choix de l’utilisateur dans des variables. Un bouton « Valider le choix » permet d’appeler le viewControler correspondant.

//
//  ViewController.swift
//  pickerView
//
//  Created by Patrick Leclercq on 24/07/2018.
//  Copyright © 2018 patrick leclercq. All rights reserved.
//

import UIKit

fileprivate let composantFruits   = 0
fileprivate let composantCouleurs = 1

// Contenu du PickerView
fileprivate let listeDesFruits = [
    "Pomme",
    "Cerise",
    "Ananas",
    "Kiwi",
    "Banane"]

fileprivate let listeDesCouleurs = [
    "rouge",
    "vert",
    "mauve"]

class ViewController:   UIViewController,
                        UIPickerViewDelegate,
                        UIPickerViewDataSource {

    @IBOutlet weak var pickerView: UIPickerView!
    @IBOutlet weak var label     : UILabel!
    
    // Mémorisation des choix du pickerView
    var selectionFruit   = listeDesFruits[0]
    var selectionCouleur = listeDesCouleurs[0]
    
    // Initialisation viewController
    override func viewDidLoad() {
        super.viewDidLoad()
        pickerView.dataSource = self
        pickerView.delegate   = self
    }
    
    // ---------
    // MARK : Remplissage du PickView
    // Déclaration du nombre de composants par ligne
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 2
    }
    
    // Nombre de lignes
    // pour chaque composant
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        switch component {
        case composantFruits:
            return listeDesFruits.count
        case composantCouleurs:
            return listeDesCouleurs.count
        default:
            return 0
        }
    }
    
    // Remplissage de chaque ligne
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        switch component {
        case composantFruits :
            return listeDesFruits[row]
        case composantCouleurs :
            return listeDesCouleurs[row]
        default:
            // Si le defaut s'active,
            // il y a une erreur dans la structure des données
            return ""
        }
    }


    // -------------
    // Delegate du Picker View
    
    // Cette méthode est appelée APRES la sélection d'un élément du Picker
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        
        // Mémorisation du choix fruit/couleur
        switch component {
        case composantFruits:
            selectionFruit = listeDesFruits[row]
        case composantCouleurs:
            selectionCouleur = listeDesCouleurs[row]
        default:
            // Jamais appelé normalement ..
            print ("Problème avec le switch")
        }
        
    }
    
    // ---------------
    // Coeur de l'application
    
    // Traitement des choix sélectionnés
    func validerChoix() {
        
        let fruit = selectionFruit
        let couleur = selectionCouleur
        
        if fruit == "Pomme" && couleur == "rouge" {
            print ("Appel du viewControler PommeRouge")
        }
        else if fruit == "Pomme" && couleur == "mauve" {
            print ("Appel du viewControler PommeMauve")
        }
        else if fruit == "Kiwi" && couleur == "vert" {
            print ("Appel du viewControler KiwiVert")
        }
        else {
            print ("Aucun viewControler n'est associé à ce choix")
        }
        
    }
    
    // Action Bouton "Valider les choix"
    @IBAction func actionBouton(_ sender: Any) {
        validerChoix()
    }
    
}

Génial, effectivement on est confronté aux choix, donc par if ou switch ! :nerd_face:
Je te remercie pour ta solution.

Pas forcément. Si le nombre de choix est important, il est préférable de tout stocker dans un tableau (fruit/couleur/référence au viewControler) et d’utiliser une boucle pour rechercher une combinaison particulière.

Un amoncellement de plusieurs dizaines de tests imbriqués est un magnifique nid à bugs.

Pourquoi places-tu ces variables, constantes avant la classe du viewController ?

fileprivate let composantFruits = 0
fileprivate let composantCouleurs = 1

// Contenu du PickerView
fileprivate let listeDesFruits = [
“Pomme”,
“Cerise”,
“Ananas”,
“Kiwi”,
“Banane”]

fileprivate let listeDesCouleurs = [
“rouge”,
“vert”,
“mauve”]

Cordialement, Didier

Parce que j’aime bien séparer la partie “déclarative” des données, de la partie “lignes de code”. Je trouve ça plus lisible, surtout pour un exemple pédagogique.

Normalement c’est une mauvaise idée, les variables globales étant visibles dans la totalité des fichiers de l’application. Pas top pour la sécurité et l’indépendance des classes.

Mais fileprivate est un attribut spécial signifiant “ceci est privé à ce fichier de code. Les autres fichiers de l’application ne peuvent y accéder”. Seul le viewControler de ce fichier peut y avoir accès.