2012-05-30 15 views
21

Bardzo często sprawdzałem to pytanie, ale wciąż nie jestem pewien, czy to możliwe, czy nie. Zasadniczo chcę utworzyć UIPickerView, który jest ciągły w tym sensie, że można go zakręcić na zawsze i nigdy nie dojdziesz do końca (ponieważ po ostatniej wartości następuje pierwsza wartość).Jak zrobić okrągły UIPickerView (iPhone/iPad)?

Rozejrzałem się po Internecie i wydaje się, że istnieje wiele różnych hacków, aby osiągnąć pożądany efekt. Jednak wiele z tych rozwiązań wydaje się zwiększać liczbę wierszy w UIPickerView, aby skłonić użytkownika do myślenia, że ​​UIPickerView jest ciągły (jednak w rzeczywistości, gdyby dalej przewijali, w końcu dotarliby do końca).

To, czego szukam, to sposób na stworzenie UIPickerView, który jest naprawdę nieskończony w tym sensie, że nigdy nie dotrzesz do końca, jeśli będziesz przewijać przez kilka dni, tygodni, miesięcy lub lat. Nie przejmuję się zbytnio, jeśli rozwiązanie jest hackerem, ponieważ rozumiem, że Apple nie dostarczyło jeszcze sposobu na osiągnięcie tego efektu.

Czy ktoś może doradzić, jak to zrobić (lub wskazać przynajmniej we właściwym kierunku)?

Odpowiedz

4

naprawdę myślę, że tylko siekać można zrobić z natywnym UIPickerView jest opisany tutaj:

How do you make an UIPickerView component wrap around?

Innym sposobem robią naprawdę zapętlony kompletacji jest wdrożenie go przez siebie.

Widziałem osoby, które zostały wdrożone za pomocą cocos2d, czyli opartego na OpenGL. Myślę, że możesz spróbować zrobić to za pomocą UIKit, jeśli naprawdę potrzebujesz.

Albo po prostu zapomnij o tym i zrób zestaw z wierszami NSIntegerMax z powtarzalną zawartością. Myślę, że nikt nie zakręci tego do końca.

+0

Umieszczenie NSIntegerMax generalnie spowoduje awarię programu. Czuję, że odpowiedź Oliego jest lepsza i rozsądniejsza w przypadku użyteczności i pamięci. –

0

Hm .. Rozglądałem się i istnieje kilka linków do kilku możliwości, z których najważniejsza to jedna: The Abusive Pickerview, podstawową ideą jest zapełnianie widoku picker z 3 zestawami danych i start i zestaw centralny. Za każdym razem, gdy użytkownik przewinie do środka jednego z górnych lub dolnych zestawów, ustawiasz wartość wiersza z powrotem na środek zestawu centralnego! Wydaje się bardziej autentyczny niż stworzenie naprawdę długiej listy, która stworzy iluzję nieskończoności. To rozwiązanie może być najbardziej efektywne i proste w rozwiązywaniu problemu nieskończonego podglądania! Mam nadzieję, że to pomogło!

+0

Ogólnie nie powinieneś kopiować i wklejać swoich odpowiedzi z innych postów http://stackoverflow.com/questions/10815435/how-to-make-a-circular-uipickerview-iphone-ipad – pasawaya

+0

Hm .. Nie zrobiłem tego faktycznie zobacz ten post ... – wayway

2

Jest to możliwe. Oto, jak możesz to zrobić. Najpierw ustaw zegar. Załóżmy, że int maxNumber jest zmienną instancji ustawioną na dowolną dowolną wartość.

- (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]; 
} 

W metodzie nagrywania z timerem sprawdź, czy wyświetla się widok "krawędzi" widoku uipicker.

- (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; 
    } 
} 
} 

Uwaga to działa bo [self.infinitePickerView viewForRow:i forComponent:0]; zwraca UIView tylko wtedy, gdy jest to widoczne.

Oczywiście Twój UIPickerViewDelegate muszą stosować się coś

- (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; 
} 

nadzieję, że to działa !! :) Powodzenia!

+0

wygląda jak fajny hack. @ The Crazy Chimp daj nam znać, czy to działa. –

3

Znajdź niestandardowy UIPickerView klasę, która działa bardzo dobrze i jest bardzo łatwe do wdrożenia here

0

Wydaje mi się, że rozwiązania wymagające dużych ilości danych jest nadziewana w pickerView są marnotrawstwem. Poniższe rozwiązanie wykorzystuje inteligentne zamiast pamięci.

Jedyne wiersze, które należy wypełnić, to wiersze widoczne w widoku i wiersz bezpośrednio poprzedzający pierwszy oraz wiersz bezpośrednio następujący po ostatnim. Gdy użytkownik przewija komponent, pickerView: titleForRow: forComponent: jest wywoływany dla każdego wiersza, który przewija.

Rozwiązaniem jest aktualizacja danych w pickerView: titleForRow: forComponent: a następnie wywołanie odpowiedniej metody w celu ponownego załadowania danych, aby istniała, gdy widok picker przewija jeszcze jeden znacznik.

2

Nie jest rodowitym kompletacji że owija Można fałszywy to coś wzdłuż tych linii (nie tak z iOS7.1 anyway.):

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]; 
    } 
} 

Będziesz musiał dostosować i regulować, aby dopasować swoje potrzeb, oczywiście, ale to jest jego podstawowy sens.

Powodzenia!

0

Wiem, że to stare pytanie, ale właśnie znalazłem to, ponieważ wdrażam je w moim własnym projekcie.

Po prostu użyj metody Morion dużej liczby elementów z powtarzającą się zawartością, a następnie za każdym razem, gdy przestanie się przewijać, zresetuj wiersz. Jedynym sposobem, w jaki ktokolwiek może się dowiedzieć, że oszukiwałeś, jest ciągłe przewijanie bez przerwy, dopóki się nie zatrzyma, nigdy nie wywołując funkcji didSelectRow. To wymagałoby poświęcenia!

Niezależnie od tego, jak to zrobić, wydaje mi się, że to będzie czuć się nieco hacky, & musi to być najprostszy siekać ...

0

zrobiłem cykliczną tableView oparciu o UIScrollView. I na podstawie tego tableView, ponownie implementuję UIPickerView. Być może zainteresuje Cię to. Ten widok selektora ma całą funkcję, która jest dostępna pod UIPickerView, ale oferuje także wiele nowych funkcji, a niestandardowy widok tego sortowania jest znacznie łatwiejszy.

https://github.com/danleechina/DLPickerView

i mieć świadomość, że ten DLPickerView cyklicznie zwoju jest naprawdę przewijanie cyklicznie. Cała magia powstała z powodu innej klasy DLTableView.

0

użyłem pickerView Wybór stworzyć okrągły jedno:

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

bardzo proste rozwiązanie, które pozwoli u pomyśleć nie ma końca zdania kompletacji, by skala się tablicy i zrobić moduł odebrać odzwierciedlał pozycja z tablicy

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] 
}