2014-09-26 15 views
10

Ich entwickle gerade eine Anwendung mit Swift, wo ich ein UIPickerView verwende, siehe unten für Bild. Momentan stoppt UIPickerView, wenn der Benutzer zu den letzten Daten gescrollt hat, aber ich möchte es nie stoppen. Ich möchte, dass es möglich ist, mit den ersten Daten zu beginnen, indem Sie weiter scrollen, wenn Sie ganz unten sind. Oder scrollen Sie nach oben, wenn Sie oben sind. Ich möchte, dass es wie Apples Countdown ist, in dem Sie jederzeit nach oben oder unten ziehen können.UIPickerView - Schleife die Daten

Wie ich will es sein:

enter image description here

Wie ist es zur Zeit:

enter image description here

Antwort

9

Es gibt vier Stufen, hier - wir einige Konstanten eingerichtet werden, die Picker Ansicht Daten und halten Bit der Konfiguration, dann fügen wir UIPickerViewDataSource und UIPickerViewDelegate Methoden hinzu, und wir werden mit der viewDidLoad Initialisierung enden.

Zuerst wird die Konfiguration:

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 

Notiere die pickerViewMiddle konstant - es berechnet es sehr einfach zu machen unseren aktuellen Wert aus der Reihe versetzt zu bekommen. Auf die Datenquelle - wir wirklich nur einen Titel für jede Zeile zur Verfügung stellen müssen, aber wir werden eine Hilfsmethode fügen Sie eine Zeilennummer auf einen Wert aus dem Array zu konvertieren:

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

Und schließlich: ‚Wir ll eingerichtet, um die Delegierten:

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

} 

zu initialisieren, in Ihrem viewDidLoad gesetzt den Delegierten und Datenquelle und dann in der Mitte des Picker auf die richtige Zeile bewegen:

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

Dank! Es funktioniert perfekt! – ThomasGulli

+1

Wie in [diese Antwort] (http://stackoverflow.com/a/367436/172218) erwähnt, wird bei der Einstellung der Anzahl der Zeilen im Picker auf "jede große Zahl" VoiceOver mit "[Element] von [große Zahl ] ", was ein Zugänglichkeitsproblem ist. Irgendwie in der Nähe? –

+0

Hallo, Nate! Wo deklarieren Sie Ihre Konfiguration? Ich habe es in meiner Klasse deklariert, aber geben Sie mir einen Fehler mit Instanz kann nicht in meiner Klasse verwendet werden. –

2

Dies wurde bereits beantwortet hier: How do you make an UIPickerView component wrap around?

Die Grundidee besteht darin, dass Sie einfach eine Auswahlansicht mit einer ausreichend großen Anzahl von sich wiederholenden Zeilen erstellen, damit der Benutzer wahrscheinlich nie das Ende erreicht. In der obigen Antwort gibt es ein Problem mit wie die Anzahl der Zeilen erstellt wird, also habe ich dieses Stück bearbeitet und die verbleibende Antwort unten zur Verfügung gestellt. Dies ist Objective-C, so dass Sie es zu raschen für Ihre Zwecke umwandeln müssen ...

@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