2012-05-30 10 views
21

Ho dato un'occhiata a questa domanda molto ma non sono ancora chiaro se sia possibile o meno. In sostanza, quello che voglio fare è creare un UIPickerView che sia continuo nel senso che è possibile girarlo per sempre e non si arriverà mai alla fine di esso (poiché l'ultimo valore è seguito dal primo valore).Come creare un UIPickerView circolare (iPhone/iPad)?

Ho dato un'occhiata in giro online e sembra che ci sia una grande varietà di hack per ottenere l'effetto desiderato. Tuttavia molte di queste soluzioni sembrano aumentare il numero di righe nel UIPickerView per indurre l'utente a pensare che lo UIPickerView sia continuo (tuttavia, in realtà se continuassero a scorrere avrebbero infine raggiunto la fine).

Quello che voglio è un modo per creare un UIPickerView che sia veramente infinito nel senso che non si arriverà mai alla fine se continui a scorrere per giorni, settimane, mesi o anni. Non mi dispiace troppo se la soluzione è un trucco, poiché capisco che Apple non ha ancora fornito un modo per ottenere l'effetto.

Per favore qualcuno può consigliare un modo per farlo (o indicarmi almeno la giusta direzione)?

risposta

4

credo davvero, che l'unico hack può fare con UIPickerView nativa è descritto qui:

How do you make an UIPickerView component wrap around?

L'altro modo fanno picker davvero loop è quello di attuare da soli.

Ho visto i selettori implementati con cocos2d, ovvero basati su OpenGL. Penso che tu possa provare a farlo usando UIKit se davvero ne hai bisogno.

Oppure dimenticarlo e creare un selettore con righe NSIntegerMax con contenuto ripetibile. Penso che nessuno lo farà girare fino alla fine.

+0

Inserire NSIntegerMax interromperà generalmente il programma. Sento che la risposta di Olie è migliore e ragionevole in caso di usabilità e memoria. –

0

Hm .. Mi sono guardato intorno, e ci sono un paio di link a poche possibilità, la più eccezionale è questa: The Abusive Pickerview, l'idea di base è che si popola il pickerview con 3 set di dati e inizio e il centro impostato. Ogni volta che l'utente scorre al centro di uno dei set superiore o inferiore, si imposta il valore della riga sul centro del set centrale! Sembra essere più genuino, quindi fare una lista davvero lunga che creerà l'illusione dell'infinito. Questa soluzione potrebbe essere la soluzione più efficace e semplice per risolvere il problema di pickerview infinito! Spero che questo ha aiutato!

+0

Generalmente, non dovresti copiare e incollare le tue risposte da altri post http://stackoverflow.com/questions/10815435/how-to-make-a-circular-uipickerview-iphone-ipad – pasawaya

+0

Hm .. Non l'ho fatto effettivamente visualizzare questo post ... – wayway

2

È possibile. Ecco come puoi farlo. Per prima cosa imposta un timer. Supponiamo che int maxNumber sia una variabile di istanza impostata su un valore arbitrario.

- (void) viewWillAppear:(BOOL)animated{ 
    [super viewWillAppear:animated]; 
    [self.timer invalidate]; 
    self.timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(timerFireMethod:) userInfo:nil repeats:YES]; 

} 

- (void) viewWillDisappear:(BOOL)animated{ 
    [self.timer invalidate]; 
    [super viewWillDisappear:animated]; 
} 

- (void)viewDidLoad 
{ 
[super viewDidLoad]; 
// Do any additional setup after loading the view, typically from a nib. 
[self.infinitePickerView selectRow:(int)maxNumber*5 inComponent:0 animated:YES]; 
} 

Nel metodo di attivazione del timer, controllare se viene visualizzata una qualsiasi delle viste 'edge' del proprio uipickerview.

- (void)timerFireMethod:(NSTimer*)theTimer{ 
int rowSelected = [self.infinitePickerView selectedRowInComponent:0];  
for (int i=0; i<= 20; i++) { 
    UIView * viewBelow = [self.infinitePickerView viewForRow:i forComponent:0]; 
    UIView * viewAbove = [self.infinitePickerView viewForRow:maxNumber*10-20+i forComponent:0]; 
    if(viewBelow!=nil || viewAbove!=nil){ 
     int middlePosition = maxNumber * 5 + (rowSelected % maxNumber); 
     [self.infinitePickerView selectRow:middlePosition inComponent:0 animated:NO]; 
     break; 
    } 
} 
} 

Nota questo funziona perché [self.infinitePickerView viewForRow:i forComponent:0]; restituisce un UIView solo se è visibile.

Naturalmente il vostro UIPickerViewDelegate devono usare qualcosa come

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{ 
    return maxNumber * 10; //returning a large number 
} 

//You cannot use this method 
/* 
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{} 
You have to use the method below in lieu of it 
*/ 

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view{ 

UILabel * label; 

if (!view) { 
    label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.infinitePickerView.bounds.size.width, 30)]; 
}else { 
    label = (UILabel *) view;  
} 
[label setText:[NSString stringWithFormat:@" %d", row % maxNumber]]; 
return label; 
} 

Spero che questo funziona !! :) In bocca al lupo!

+0

sembra un bel trucco. @The Crazy Chimp fateci sapere se funziona. –

3

Trova il UIPickerView classe personalizzata che funziona molto bene ed è molto facile da implementare here

0

Mi sembra che le soluzioni che richiedono grandi quantità di dati essere farcito nella pickerView sono uno spreco. La seguente soluzione utilizza l'intelligenza invece della memoria.

Le uniche righe che devono essere compilate sono le righe visibili nella vista e la riga immediatamente precedente alla prima e la riga immediatamente successiva all'ultima. Quando l'utente scorre un componente, pickerView: titleForRow: forComponent: viene chiamato per ogni riga che scorre per.

Quindi la soluzione è aggiornare i dati in pickerView: titleForRow: forComponent: e quindi chiamare il metodo appropriato per ricaricare i dati in modo che siano lì quando il pickerview scorre un altro tick.

2

Non c'è un selettore nativo che avvolge Puoi fingere questo qualcosa in questo senso (non come di iOS7.1 comunque.):

NSArray *picks = @[ @"zero", @"one", @"two", @"three" ]; // 4 entries 

// ... 

- (NSInteger)pickerView:(UIPickerView *)pickerView 
numberOfRowsInComponent:(NSInteger)component 
{ 
    return (3 * [picks count]); // we're very tricky, displaying only 
           // ...the SECOND set of entries, to 
           // ... give the impression of wrap-around 
} 

// ... 

- (NSString *)pickerView:(UIPickerView *)pickerView 
      titleForRow:(NSInteger)row 
      forComponent:(NSInteger)component 
{ 
    // All "3" sets of entries have the same values; 
    // this is what gives the appearance of wrap-around. 
    int titleRow = row % [picks count]; 
    return [picks objectAtIndex: titleRow]; 
} 

// ... 

- (void)pickerView:(UIPickerView *)pickerView 
     didSelectRow:(NSInteger)row 
     inComponent:(NSInteger)component 
{ 
    // If the wheel turns to outside our 2nd-set range, 
    // ...set it to the matching item in the 2nd set. 
    // In this way, we always display what looks like a wrap-around. 
    int count = [picks count]; 
    if ((row < count) 
    || (row > (count * 2)) 
    { 
     [pickerView selectRow: (row % count) inComponent: component animated: NO]; 
    } 
} 

Dovrete modificare e regolare per adattare il vostro ha bisogno, ovviamente, ma questo è l'essenza di base di esso.

Buona fortuna!

0

So che è una vecchia domanda, ma l'ho appena trovata mentre la sto implementando nel mio progetto.

Basta usare il metodo di Morion per un numero elevato di elementi con contenuti ripetuti, quindi ogni volta che si interrompe lo scorrimento, reimpostare la riga. L'unico modo in cui qualcuno potrà mai capire di aver imbrogliato è se scorrono continuamente senza interruzione finché non si arresta, senza mai chiamare la funzione didSelectRow. Ci vorrebbe un po 'di dedizione!

Indipendentemente da come lo si fa, mi sembra che sta andando a sentire un po 'hacky, & questo deve essere il più semplice mod ...

0

ho fatto un tableView ciclica basata su UIScrollView. E basato su questo TableView, re-implemento UIPickerView. Potresti essere interessato a questo. E questa vista di selezione ha tutte le funzionalità di UIPickerView, ma offre anche molte nuove funzionalità e la visualizzazione personalizzata di questa selezione è molto più semplice.

https://github.com/danleechina/DLPickerView

Ed essere consapevoli di che questo DLPickerView rotolo ciclicamente è davvero lo scorrimento ciclicamente. Tutta la magia è accaduta a causa di un'altra classe DLTableView.

0

Ho usato pickerView Selection per creare uno circolare: soluzione molto semplice

import UIKit 
    class ViewController:   
UIViewController,UIPickerViewDelegate,UIPickerViewDataSource 
{ 
@IBOutlet weak var picker: UIPickerView! 
@IBOutlet weak var myLabel: UILabel! 

let numbers = [0,1,2,3,4,5,6,7,8,9] 

override func viewDidLoad() 
{ 
    super.viewDidLoad() 
    // A.Select Second Row 
    picker.selectRow(1, inComponent: 0, animated: false) 
} 
func numberOfComponents(in pickerView: UIPickerView) -> Int 
{ 
    return 1 
} 
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int 
{ 
    //B. Add 2 rows to your array count 
    return numbers.count + 2 
} 
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? 
{ 
    var rowTitle = "" 
    switch row 
    { 
    case 0: 
     // C. Set first row title to last component of the array. 
     // This row is not visible to the user as it is hidden by the   

     //selection in ViewDidLoad 
     rowTitle = "\(numbers.last!)" 
    case numbers.count + 1: 
     //D. Set last row title to first array component 
     rowTitle = "\(numbers.first!)" 
    default: 
     // E. Remember [row - 1] to avoid errors 
     rowTitle = "\(numbers[row - 1])" 
    } 
    return rowTitle 
} 
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) 
{ 
    var theText = "" 
    switch row 
    { 
    case 0: 
     //F. Select Row at array count to load the last row 
     pickerView.selectRow(numbers.count , inComponent: 0, animated: false) 
     theText = = "\(numbers.last!)" 
    case numbers.count + 1: 
    //G. This Selection will set the picker to initial state 
     pickerView.selectRow(1, inComponent: 0, animated: false) 
     theText = "\(numbers.first!)" 
    default: 
     theText = "\(numbers[row - 1])" 
    } 
    myLabel.text = theText 

} 

    } 
0

A che renderà u pensa non c'è fine della vista raccoglitrice, dalla scala la matrice e rendere modulo scegliere il corrispondeva elemento dall'array

override func viewDidLoad(){ 
    super.viewDidLoad() 
    self.yourArray.selectRow((yourArray.count*100)/2, inComponent: 0, animated: false) 
} 

func pickerView(_ pickerView: UIPickerView, numberOfRowaInComponent component: Int) -> Int{ 
    return yourArray.count*100 
} 

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int)->String{ 
    return yourArray[row % yourArray.count] 
} 
Problemi correlati