2012-05-30 45 views
21

我已經仔細查看了這個問題,但是我仍然不清楚它是否可行。基本上我想要做的是創建一個連續的UIPickerView,因爲您可以永久旋轉它,並且永遠不會到達它的末尾(因爲最後一個值後面跟着第一個值)。如何製作圓形UIPickerView(iPhone/iPad)?

我已經在網上看了一遍,似乎有各種各樣的黑客達到預期的效果。然而,許多這些解決方案似乎增加了UIPickerView中的行數,以誘使用戶認爲UIPickerView是連續的(但是,實際上,如果他們繼續滾動,它們最終將達到結束)。

我所追求的是創建一個真正無限的UIPickerView的方法,如果您持續滾動數天,數週,數月或數年,您永遠無法達到最終目的。如果解決方案是黑客,我不介意太多,因爲我知道蘋果尚未提供實現該效果的方式。

請有人建議這樣做(或至少指出我在正確的方向)?

回答

4

我真的覺得,那只是破解你可以用本地UIPickerView做的是這裏描述:

How do you make an UIPickerView component wrap around?

另一種方式讓你真的環形選擇器是由自己來實現它。

我看到採用cocos2d實現的採集器,即基於OpenGL的採集器。我想,如果你真的需要,你可以嘗試使用UIKit。

或者只是忘記它,並與NSIntegerMax行與可重複的內容選擇器。我認爲沒有人會把它旋轉到最後。

+0

放置NSIntegerMax通常會使程序崩潰。我覺得在可用性和記憶的情況下,Olie的答案是更好更合理的答案。 –

0

嗯..我一直在環顧四周,有幾個可能性的鏈接,最突出的是這一個:The Abusive Pickerview,基本思想是你用3套數據填充pickerview,開始和中心設置。無論何時用戶滾動到頂部或底部集合的中心,您都可以將行值設置回中間集合的中心!這似乎是更真實的,然後製作一個很長的清單,這將創造無限的幻覺。這個解決方案對解決無限pickerview問題可能是最有效和最簡單的!希望這有助於!

+0

通常,你不應該複製並粘貼你的答案從其他帖子http://stackoverflow.com/questions/10815435/how-to-make-a-circular-uipickerview-iphone-ipad – pasawaya

+0

嗯..我沒有實際查看此帖... – wayway

2

這是可能的。這是你如何做到的。首先設置一個計時器。我們假設int maxNumber是一個設置爲某個任意值的實例變量。

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

在timer fire方法中,檢查是否顯示了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; 
    } 
} 
} 

注意這個工程,因爲[self.infinitePickerView viewForRow:i forComponent:0];只返回,如果它是可見的UIView。

當然你UIPickerViewDelegate必須使用是這樣的

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

希望這個作品! :) 祝你好運!

+0

看起來像一個很好的黑客。 @瘋狂的黑猩猩讓我們知道它是否有效。 –

3

找到自定義UIPickerView類工作得很好,是很容易實現 here

0

在我看來,這需要大量數據的解決方案塞到pickerView是浪費的。以下解決方案使用智能而不是內存。

需要填充的唯一行是視圖中可見的行以及緊接着第一行之前的行和緊接着最後一行之後的行。當用戶滾動一個組件時,pickerView:titleForRow:forComponent:被每個滾動的行調用。

因此,解決方案是更新pickerView:titleForRow:forComponent中的數據,然後調用相應的方法重新加載數據,以便pickerview在滾動一個更多的時間點時出現在那裏。

2

沒有一個包裝了本地選擇器,您可以假冒該由這些方針的東西(不作爲iOS7.1的反正。):

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

你必須要調整和調整,以適應您的當然需要,但這是它的基本要點。

祝你好運!

0

我知道這是一個老問題,但我剛剛在我自己的項目中實現它時發現它。

只需使用Morion的大量重複內容項目的方法,然後每次停止滾動時重置該行。任何人都會發現自己欺騙的唯一方法是,如果他們連續滾動而不停頓,直到停止,則永遠不會調用didSelectRow函數。這需要一些奉獻精神!

不管你怎麼做,在我看來,它的會覺得有點哈克,&這一定是最簡單的黑客...

0

我已經根據UIScrollView循環的tableView。並基於這個tableView,我重新實現了UIPickerView。您可能對此感興趣。這個選擇器視圖具有UIPickerView的所有功能,但也提供了許多新功能,並且自定義此選取器視圖更容易。

https://github.com/danleechina/DLPickerView

並意識到這DLPickerView循環滾動的是真正循環滾動。所有的魔法都是因爲另一個課程DLTableView而發生的。

0

我用pickerView選擇創建一個圓形之一:

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

一個非常簡單的解決方案,這將使ü認爲不存在選擇器視圖的結束,通過按比例放大的陣列中,並使模量挑對應來自陣列的項目

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