UIPickerView - 循环数据
Posted
技术标签:
【中文标题】UIPickerView - 循环数据【英文标题】:UIPickerView - Loop the data 【发布时间】:2014-09-26 15:26:00 【问题描述】:我目前正在使用 Swift 开发一个应用程序,其中我使用 UIPickerView,请参见下面的图片。目前 UIPickerView 在用户滚动到最后一个数据时停止,但我希望它永远不会停止。我希望可以从第一个数据开始,只需在您处于底部时继续滚动即可。或在顶部时向上滚动。我希望它像 Apple 的 Countdown 一样,您可以随时向上或向下拖动。
我想要的样子:
目前的情况:
【问题讨论】:
【参考方案1】:这里有四个步骤——我们将设置一些常量来保存选择器视图数据和一些配置,然后我们将添加 UIPickerViewDataSource
和 UIPickerViewDelegate
方法,我们将结束viewDidLoad
初始化。
一、配置:
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
注意pickerViewMiddle
常量——计算它可以很容易地从行偏移中获取我们的当前值。关于数据源——我们实际上只需要为每一行提供一个标题,但我们将添加一个帮助方法来将行号转换为数组中的值:
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))"
最后我们将设置委托:
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)")
要初始化,请在您的 viewDidLoad
中设置委托和数据源,然后移动到选择器中间的正确行:
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)
【讨论】:
正如this answer 中提到的,将选取器中的行数设置为“任何大数字”会破坏 VoiceOver,给出“[大数字] 的 [项目]”,这是一个可访问性问题。有什么办法吗? 嗨,内特!你在哪里声明你的配置?我在课堂上声明了它,但是给我一个错误,实例不能在我的课堂上使用。 嗨,Nate,你能在 C# 中将它转换为 Xamarin.ios,因为我遇到了同样的问题。但我不知道目标c。【参考方案2】:这里已经回答了这个问题:How do you make an UIPickerView component wrap around?
基本思想是,您只需创建一个选择器视图,其中包含足够多的重复行,用户可能永远不会到达末尾。在上面的答案中,存在如何创建行数的问题,因此我编辑了该部分并在下面提供了剩余的答案。这是objective-c,因此您需要将其转换为swift以供您使用...
@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
【讨论】:
以上是关于UIPickerView - 循环数据的主要内容,如果未能解决你的问题,请参考以下文章
原型 tableviewcell 内的 UIPickerView 没有选择指示器