2014-12-24 10 views
21

Ho 2 controller UIPicker in uno dei controller di visualizzazione. Posso far sì che uno funzioni, ma quando aggiungo un secondo, la mia app si arresta in modo anomalo. Ecco il codice che uso per una vista di selezione:Come utilizzare 2 UIPickerView in un controller di visualizzazione?

import UIKit 

class RegisterJobPosition: UIViewController, UIPickerViewDelegate{ 

@IBOutlet weak var positionLabel: UILabel! 

var position = ["Lifeguard", "Instructor", "Supervisor"] 

override func viewDidLoad() { 
    super.viewDidLoad() 
    // Do any additional setup after loading the view, typically from a nib. 

} 

override func didReceiveMemoryWarning() { 
    super.didReceiveMemoryWarning() 
    // Dispose of any resources that can be recreated. 
}  

func numberOfComponentsInPickerView(PickerView: UIPickerView!) -> Int 
{ 
    return 1 
} 

func pickerView(pickerView: UIPickerView!, numberOfRowsInComponent component: Int) -> Int 
{ 
    return position.count 
} 

func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! 
{ 
    return position[row] 
} 

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

    positionLabel.text = position[row] 
} 
} 

Ora, come posso far funzionare un secondo controller? Dire che il mio secondo PickerView si chiama location (l'altro è chiamato position). Ho provato a duplicare il codice nei metodi PickerView per location ma non funziona.

Sto usando Swift.

+0

Avrete bisogno di un modo per distinguere tra loro due se il controller di visualizzazione è l'unico delegato per la gestione dell'interazione dell'utente. Puoi pubblicare il codice che stai utilizzando per differenziarli? – andrewcbancroft

+0

Ho appena duplicato il codice. Ad esempio, nel metodo numberOfRowsInComponent, ho appena inserito: return location.count – dom999999

+0

Questa parte ha senso. Ma come stai programmando a livello di codice a quale istanza di picker stai restituendo un conteggio? Se hai due istanze di selezione che inviano messaggi al tuo controller di visualizzazione singola (delegato), è necessario un modo per identificare i raccoglitori in modo da poter eseguire la logica di derivazione appropriata e restituire il conteggio corretto per il selezionatore corretto. – andrewcbancroft

risposta

17

Sulla base delle informazioni che ho nella domanda, direi che è necessario impostare i metodi di origine dati & delegati per gestire la possibilità di distinguere tra quale istanza di selezione li chiama.

Using the tag property nella vista di selezione è una strategia.

Ci dovrebbero essere alcune istruzioni if ​​/ else o switch nei metodi che hanno una logica diversa a seconda che si tratti della posizione o del selettore di posizione a cui si fa riferimento.

+1

Per quanto riguarda le istruzioni if ​​/ else, come potrei ottenere che una variabile diventi un valore che indica la posizione o il selettore di posizione da utilizzare? – dom999999

+0

Quindi, se si imposta il tag sui selettori nello storyboard, è possibile testarlo nel metodo di callback. Vedete che il primo parametro nel metodo è un pickerView? Puoi controllare pickerView.tag ed eseguire la giusta logica in base alla correlazione del tag con l'interfaccia utente e il tuo array di dati. – andrewcbancroft

48

Ecco la mia soluzione: - sulla Storyboard, aggiungere 2 pickerView alla vista - impostare il tag prima picker's come # 1 & # 2 per il secondo selettore sotto l'Attributi ispettore - CTRL + trascina da ciascun selettore per l'icona in alto gialla View controller e scegliere dataSource.Repeate la stessa scelta delegato - Ripetere le quanto sopra per l'altra raccoglitrice troppo - aggiungere pickerView & pickerviewdelegation alla classe ViewController:

class ViewController: UIViewController,UIPickerViewDataSource,UIPickerViewDelegate { 
  • nella classe ViewController, creare array vuoti per i raccoglitori:

    var picker1Options = [] 
    var picker2Options = [] 
    
  • su viewDidLoad() il metodo, popolano gli array con il contenuto:

    picker1Options = ["Option 1","Option 2","Option 3","Option 4","Option 5"] 
    picker2Options = ["Item 1","Item 2","Item 3","Item 4","Item 5"] 
    
  • implementare i metodi pickerView delegato &:

    func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int { 
        return 1 
    } 
    
    func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 
        if (pickerView.tag == 1){ 
         return picker1Options.count 
        }else{ 
         return picker2Options.count 
        } 
    } 
    
    func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! { 
        if (pickerView.tag == 1){ 
         return "\(picker1Options[row])" 
        }else{ 
         return "\(picker2Options[row])" 
        } 
    } 
    

Divertiti, divertiti ed esprimi la tua felicità con un segno di positività.

+1

Grazie per il suggerimento dei tag, che mi aiuta molto a utilizzare più selettori. Ora ho risolto. –

+0

Questo mi fa perdere la testa di quanto sia difficile riempire più PickerViews nello stesso ViewController. Su Android è super semplice. –

+1

Lazar K è un commento molto odioso. Non è più semplice né più complesso. È solo una strategia diversa. Su Android dovresti (o dovresti) utilizzare adattatori diversi per diversi Spinners. In realtà puoi anche utilizzare diverse origini dati e delegati su iOS. Lo suggerirei in una risposta –

0

Il mio background è su Android ma la mia risposta è molto OOP.Vorrei suggerire la creazione di classi diverse per implementare il DataSource e delegato in questo modo:

class PositionDataSourceDelegate : NSObject, UIPickerViewDelegate, UIPickerViewDataSource { 
    var position = ["Lifeguard", "Instructor", "Supervisor"] 
    var selectedPosition : String? 

    func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int { 
     return 1 
    } 

    func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 
     return position.count 
    } 

    func pickerView(pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? { 
     return position[row] 
    } 

    func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { 
     selectedPosition = position[row] 
    } 
} 

e poi un altro per la posizione:

class LocationDataSourceDelegate : NSObject, UIPickerViewDelegate, UIPickerViewDataSource { 
    var location = ["Up", "Down", "Everywhere"] 
    var selectedLocation : String? 

    func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int { 
     return 1 
    } 

    func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 
     return location.count 
    } 

    func pickerView(pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? { 
     return location[row] 
    } 

    func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { 
     selectedLocation = location[row] 
    } 
} 

poi nel vostro RegisterJobPosition è necessario creare un'istanza di ciascuno:

let positionDSD = PositionDataSourceDelegate() 
let locationDSD = LocationDataSourceDelegate() 

e assegnarli ai raccoglitori come questo:

positionPicker.dataSource = positionDSD 
positionPicker.delegate = positionDSD 
locationPicker.dataSource = locationDSD 
locationPicker.delegate = locationDSD 

ed è possibile accedere alla posizione e la posizione selezionata utilizzando:

positionDSD.selectedPosition 
locationDSD.selectedLocation 

Spero che questo voi e gli altri aiuta e sto anche la speranza per alcuni commenti costruttivi del perché questo non è "swifty"

+0

È una buona soluzione OO, ma in realtà non funziona in pratica: sono un nuovo arrivato iOS, ma nel tentativo di risolvere esattamente questo problema tutto il giorno, e mi sembra che un UIPickerViewDelegate/DataSource deve anche essere un UIViewController. Un semplice NSObject non funziona. – Fishbreath

0

Penso che il problema più grande e diverso da Java sia che Java consente facilmente che gli attributi vengano passati attraverso il costruttore. per esempio. si potrebbe dichiarare class LocationDataSourceDelegate come generico e chiamarlo genericDataSourceDelegate e rendere il costruttore accept e Array public genericDataSourceDelegate (String data []) ed essere in grado di creare una classe dove potrebbe semplicemente creare oggetti di. Basta istanziarlo e passare la posizione del costruttore come genericDataSourceDelegate (posizione)

Il problema con il tuo modello dovrai creare tante classi delegate in un programma che è un ceppo per il tuo compilatore.

1

Ho trovato che funziona.

class SecondViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource { 

    @IBOutlet weak var textbox1: UILabel! 
    @IBOutlet weak var textbox2: UILabel! 

    @IBOutlet weak var dropdown1: UIPickerView! 
    @IBOutlet weak var dropdown2: UIPickerView! 

    var age = ["10-20", "20-30", "30-40"] 
    var Gender = ["Male", "Female"] 

    func numberOfComponents(in pickerView: UIPickerView) -> Int { 
     return 1 
    } 

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 
     var countrows : Int = age.count 
     if pickerView == dropdown2 { 
      countrows = self.Gender.count 
     } 

     return countrows 
    } 

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { 
     if pickerView == dropdown1 { 
      let titleRow = age[row] 
      return titleRow 
     } else if pickerView == dropdown2 { 
      let titleRow = Gender[row] 
      return titleRow 
     } 

     return "" 
    } 

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { 
     if pickerView == dropdown1 { 
      self.textbox1.text = self.age[row] 
     } else if pickerView == dropdown2 {    
      self.textbox2.text = self.Gender[row] 
     } 
    } 
} 
Problemi correlati