UIPickerView - объединение данных

В настоящее время я разрабатываю приложение, использующее Swift, где я использую UIPickerView, как показано ниже для изображения. В настоящее время UIPickerView останавливается, когда пользователь прокручивается до последних данных, но я не хочу, чтобы он никогда не останавливался. Я хочу, чтобы можно было начать с первых данных, просто продолжайте прокручивать, когда вы находитесь внизу. Или прокрутите вверх, когда наверху. Я хочу, чтобы это было похоже на Apple Countdown, где вы можете перетаскивать вверх или вниз, когда захотите.

Как я хочу:

enter image description here

Как это в настоящее время:

enter image description here

Ответ 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)

Ответ 2

Здесь уже был дан ответ: Как вы обмениваете компонент UIPickerView?

Основная идея заключается в том, что вы просто создаете представление выбора с достаточно большим количеством повторяющихся строк, которые пользователь, вероятно, никогда не достигнет конца. В приведенном выше ответе возникает проблема с тем, как создается количество строк, поэтому я отредактировал эту часть и предоставил оставшийся ответ ниже. Это objective-c, поэтому вам нужно будет преобразовать его в быстрое для ваших целей...

@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