21

我已经对这个问题进行了很多研究,但是我仍然不清楚这是否可能。基本上我想做的是创建一个UIPickerView连续的,你可以永远旋转它并且你永远不会到达它的结尾(因为最后一个值后面跟着第一个值)。

我在网上浏览了一下,似乎有各种各样的黑客来达到预期的效果。然而,许多这些解决方案似乎增加了行数,UIPickerView以诱使用户认为它UIPickerView是连续的(然而,实际上,如果他们继续滚动,他们最终会到达终点)。

我所追求的是一种创建真正无限的 UIPickerView 的方法,因为如果你持续滚动几天、几周、几个月或几年,你将永远不会到达终点。如果解决方案是黑客攻击,我不会太介意,因为我知道 Apple 尚未提供实现该效果的方法。

请有人就这样做的方式提出建议(或至少指出我正确的方向)?

4

10 回答 10

4

我真的认为,您可以使用本机 UIPickerView 进行的唯一破解如下所述:

你如何让 UIPickerView 组件环绕?

另一种制作真正循环选择器的方法是自己实现它。

我看到了用 cocos2d 实现的选择器,它是基于 OpenGL 的。我认为,如果你真的需要,你可以尝试使用 UIKit 来实现。

或者干脆忘记它并使用具有可重复内容的 NSIntegerMax 行创建一个选择器。我认为没有人会旋转到最后。

于 2012-06-02T10:39:39.723 回答
3

在这里UIPickerView找到运行良好且很容易实现 的自定义类

于 2012-10-04T09:56:53.643 回答
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];
    }
}

当然,您必须进行调整以适应您的需求,但这是它的基本要点。

祝你好运!

于 2014-05-15T02:08:23.877 回答
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];
}

在计时器触发方法中,检查是否显示了 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;
}

希望这有效!:) 祝你好运!

于 2012-06-06T17:55:23.553 回答
0

嗯..我一直在环顾四周,有几个链接指向一些可能性,最突出的是这个:滥用 Pickerview,基本思想是你用 3 组数据填充 pickerview 并开始中心集。每当用户滚动到顶部或底部集的中心时,您将行值设置回中心集的中心!这似乎比列出一个很长的清单更真实,这会产生无限的错觉。对于解决无限pickerview问题,此解决方案可能是最有效和最简单的!希望这有帮助!

于 2012-06-06T14:51:04.570 回答
0

It seems to me that solutions requiring large amounts of data be stuffed into the pickerView are wasteful. The following solution uses smarts instead of memory.

The only rows that need to be populated are the rows visible in the view and the row immediately preceding the first one and the row immediately following the last one. When the user scrolls a component, pickerView:titleForRow:forComponent: is called for each row that scrolls by.

So the solution is to update the data in pickerView:titleForRow:forComponent: and then call the appropriate method to reload the data so that it is there when the pickerview scrolls one more tick.

于 2013-01-13T01:45:30.753 回答
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]
}
于 2017-12-27T21:34:00.560 回答
0

我制作了一个基于UIScrollView. 并且基于这个tableView,我重新实现了UIPickerView. 你可能对此感兴趣。而且这个picker view拥有所有的特性UIPickerView,而且还提供了很多新的特性,自定义这个picker view就容易多了。

https://github.com/danleechina/DLPickerView

请注意,这个 DLPickerView 循环滚动实际上是循环滚动。所有的魔法都是因为另一个班级而发生的DLTableView

于 2016-11-14T06:31:46.467 回答
0

我使用 pickerView Selection 创建了一个圆形:

   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

}

  }
于 2017-02-06T12:55:49.360 回答
0

我知道这是一个老问题,但我只是在我自己的项目中实现它时才发现它。

只需使用 Morion 的方法处理具有重复内容的大量项目,然后每次停止滚动时,重置行。任何人都知道你作弊的唯一方法是,如果他们连续滚动而不中断,直到它停止,从不调用 didSelectRow 函数。这需要一些奉献精神!

不管你怎么做,在我看来它会感觉有点hacky,这一定是最简单的hack......

于 2015-11-02T15:42:40.613 回答