2014-09-26 35 views
10

Tôi hiện đang phát triển một ứng dụng bằng Swift nơi tôi sử dụng UIPickerView, xem bên dưới để xem hình ảnh. Hiện tại UIPickerView dừng khi người dùng đã cuộn đến dữ liệu cuối cùng, nhưng tôi muốn nó không bao giờ dừng lại. Tôi muốn có thể bắt đầu từ dữ liệu đầu tiên bằng cách tiếp tục cuộn khi bạn ở dưới cùng. Hoặc cuộn lên khi ở trên cùng. Tôi muốn nó giống như đếm ngược của Apple, nơi bạn có thể kéo lên hoặc xuống bất cứ khi nào bạn muốn.UIPickerView - Lặp lại dữ liệu

Làm thế nào tôi muốn nó được:

enter image description here

Làm thế nào nó hiện là:

enter image description here

Trả lời

9

Sẽ có bốn bước ở đây - chúng tôi sẽ thiết lập một số hằng số để giữ dữ liệu xem bảng chọn và một bit cấu hình, sau đó chúng tôi sẽ thêm các phương thức UIPickerViewDataSourceUIPickerViewDelegate và chúng tôi sẽ kết thúc bằng việc khởi tạo viewDidLoad.

Thứ nhất, cấu hình:

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 

Lưu ý pickerViewMiddle liên tục - đó là tính toán để làm cho nó rất dễ dàng để có được giá trị hiện tại của chúng tôi từ hàng bù đắp. Vào các nguồn dữ liệu - chúng tôi thực sự chỉ cần cung cấp một tiêu đề cho mỗi hàng, nhưng chúng tôi sẽ thêm một phương pháp helper để chuyển đổi một số hàng để một giá trị từ mảng:

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))" 
    } 
} 

Và cuối cùng chúng tôi ll thiết lập các đại biểu:

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)") 
    } 

} 

để khởi tạo, trong viewDidLoad bạn thiết lập các đại biểu và nguồn dữ liệu và sau đó di chuyển đến hàng đúng ở giữa bảng chọn của bạn:

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) 
+0

Cảm ơn! Nó hoạt động hoàn hảo! – ThomasGulli

+1

Như đã đề cập trong [câu trả lời này] (http://stackoverflow.com/a/367436/172218) thiết lập số hàng trong bộ chọn cho "bất kỳ số lớn" nào lên VoiceOver, cho "[item] của [số lớn ] ", đây là sự cố trợ năng. Bất kỳ cách nào xung quanh điều này? –

+0

Xin chào, Nate! Bạn khai báo cấu hình của mình ở đâu? Tôi tuyên bố nó ở lớp của tôi, nhưng cho tôi một lỗi với ví dụ không thể được sử dụng trong lớp học của tôi. –

2

này đã được trả lời ở đây: How do you make an UIPickerView component wrap around?

Ý tưởng cơ bản là bạn chỉ cần tạo chế độ xem bộ chọn với số lượng hàng lặp lại đủ lớn mà người dùng có thể sẽ không bao giờ đạt đến kết thúc. Trong câu trả lời ở trên có một vấn đề với cách số hàng được tạo nên tôi đã chỉnh sửa phần đó và cung cấp câu trả lời còn lại bên dưới. Đây là mục tiêu-c, do đó bạn sẽ cần phải chuyển đổi nó để nhanh chóng cho mục đích của bạn ...

@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 
Các vấn đề liên quan