web-dev-qa-db-ja.com

UIPickerView-データをループします

現在、Swiftを使用してアプリを開発しています。UIPickerViewを使用しています。画像については以下を参照してください。現在、UIPickerViewは、ユーザーが最後のデータまでスクロールすると停止しますが、決して停止しないようにしたい。一番下にいるときにスクロールし続けるだけで最初のデータから開始できるようにしたい。または一番上にいるときに上にスクロールできるようにしたい。Appleのカウントダウンのように、いつでも上下にドラッグできるようにしたい。あなたが欲しい。

どうしたいのか:

enter image description here

現在の状況:

enter image description here

14
ThomasGulli

ここでは4つのステップがあります。ピッカービューデータと少しの構成を保持するための定数を設定してから、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)
10
Nate Cook

これはすでにここで回答されています: IPickerViewコンポーネントをラップアラウンドさせるにはどうすればよいですか?

基本的な考え方は、ユーザーが最後まで到達しない可能性が高い十分な数の繰り返し行を含むピッカービューを作成することです。上記の回答では、行数の作成方法に問題があるため、その部分を編集して、以下に残りの回答を提供しました。これは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
4
Brett DiDonato