2014-09-26 18 views
10

Attualmente sto sviluppando un'applicazione utilizzando Swift dove utilizzo un UIPickerView, vedi sotto per l'immagine. Attualmente UIPickerView si ferma quando l'utente ha fatto scorrere gli ultimi dati, ma io non lo voglio mai. Voglio che sia possibile iniziare dai primi dati semplicemente continuando a scorrere quando sei in fondo. O scorrere verso l'alto quando in alto. Voglio che sia come il conto alla rovescia di Apple dove puoi trascinare verso l'alto o verso il basso quando vuoi.UIPickerView - Loop dei dati

come voglio che sia:

enter image description here

Come attualmente è:

enter image description here

risposta

9

Ci saranno quattro passi qui - imposteremo alcune costanti per contenere i dati della vista raccoglitrice e di un un po 'di configurazione, quindi aggiungeremo i metodi UIPickerViewDataSource e UIPickerViewDelegate e termineremo con l'inizializzazione viewDidLoad.

In primo luogo, la configurazione:

private let pickerViewData = Array(0...59)  // contents will be 0, 1, 2, 3...59, change to whatever you want 
private let pickerViewRows = 10_000   // any big number 
private let pickerViewMiddle = ((pickerViewRows/pickerViewData.count)/2) * pickerViewData.count 

Nota la costante pickerViewMiddle - si calcola per rendere molto facile per ottenere il nostro valore corrente dalla riga offset. On per l'origine dei dati - abbiamo davvero solo bisogno di fornire un titolo per ogni riga, ma aggiungeremo un metodo di supporto per convertire un numero di riga per un valore dalla matrice:

extension ViewController : UIPickerViewDataSource { 
    func valueForRow(row: Int) -> Int { 
     // the rows repeat every `pickerViewData.count` items 
     return pickerViewData[row % pickerViewData.count] 
    } 

    func rowForValue(value: Int) -> Int? { 
     if let valueIndex = find(pickerViewData, value) { 
      return pickerViewMiddle + value 
     } 
     return nil 
    } 

    func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! { 
     return "\(valueForRow(row))" 
    } 
} 

E infine noi' ll configurare il delegato:

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

    func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 
     return pickerViewRows 
    } 

    // whenever the picker view comes to rest, we'll jump back to 
    // the row with the current value that is closest to the middle 
    func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { 
     let newRow = pickerViewMiddle + (row % pickerViewData.count) 
     pickerView.selectRow(newRow, inComponent: 0, animated: false) 
     println("Resetting row to \(newRow)") 
    } 

} 

per inizializzare, nel vostro impostare l'origine delegato e dati viewDidLoad e poi passare alla riga corretta nel bel mezzo del tuo raccoglitrice:

self.picker.delegate = self 
self.picker.dataSource = self 
let initialValue = 0 
if let row = rowForValue(initialValue) { 
    self.picker.selectRow(row, inComponent: 0, animated: false) 
} 
// or if you just want to start in the middle: 
// self.picker.selectRow(pickerViewMiddle, inComponent: 0, animated: false) 
+0

Grazie! Funziona perfettamente! – ThomasGulli

+1

Come menzionato in [questa risposta] (http://stackoverflow.com/a/367436/172218) impostando il numero di righe nel selettore su "qualsiasi numero grande" svita VoiceOver, fornendo "[elemento] di [numero grande] ] ", che è un problema di accessibilità. In qualche modo intorno a questo? –

+0

Ciao, Nate! Dove dichiari la tua configurazione? L'ho dichiarato alla mia classe, ma dammi un errore con l'istanza non può essere utilizzato nella mia classe. –

2

Questo è già stato risposto qui: How do you make an UIPickerView component wrap around?

L'idea di base è semplicemente creare una vista di selezione con un numero sufficiente di righe ripetute che l'utente probabilmente non raggiungerà mai la fine. Nella risposta sopra c'è un problema con il modo in cui viene creato il numero di righe, quindi ho modificato quel pezzo e fornito la risposta rimanente di seguito. Si tratta di Objective-C quindi sarà necessario per convertirlo in rapida per i vostri scopi ...

@implementation ViewController 
NSInteger numberItems; 
NSInteger currentValue; 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    self.pickerView.delegate = self; 
    numberItems = 60; 
    currentValue = 0; 
    [self.pickerView selectRow:(currentValue + (numberItems * 50)) inComponent:0 animated:NO]; 
    [self.view addSubview:self.pickerView]; 
} 

- (void)didReceiveMemoryWarning { 
    [super didReceiveMemoryWarning]; 
} 

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component { 
    //return NSIntegerMax; -- this does not work on 64-bit CPUs, pick an arbitrary value that the user will realistically never scroll to like this... 
    return numberItems * 100; 
} 

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component { 
    return [NSString stringWithFormat:@"%ld", row % numberItems]; 
} 

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { 
    NSInteger rowValueSelected = row % numberItems; 
    NSLog(@"row value selected: %ld", (long)rowValueSelected); 
} 

@end