Следующий код работает для iOS 10 . У меня не было возможности протестировать его на старых версиях, но я думаю, что он должен работать. Идея похожа на @ suda, но она добавляет один распознаватель касаний непосредственно в представление выбора вместо того, чтобы добавлять распознаватель касаний в каждую строку, так как это не работает на iOS7 +.
Для краткости я не включил полную реализацию протоколов UIPickerViewDataSource
и UIPickerViewDelegate
, только соответствующие части для реализации множественного выбора.
// 1. Conform to UIGestureRecognizerDelegate protocol
@interface MyViewController () <UIPickerViewDataSource, UIPickerViewDelegate, UIGestureRecognizerDelegate>
@property (nonatomic, strong) NSMutableArray *selectedArray; // To store which rows are selected
@property (nonatomic, strong) NSArray *dataArray; // Picker data
@property (weak, nonatomic) IBOutlet UIPickerView *pickerView;
@end
@implementation MyViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.selectedArray = [NSMutableArray array];
self.dataArray = @[@"Option 1", @"Option 2", @"Option 3", @"Option 4"];
// 2. Add tap recognizer to your picker view
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(pickerTapped:)];
tapRecognizer.delegate = self;
[self.pickerView addGestureRecognizer:tapRecognizer];
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return true;
}
- (void)pickerTapped:(UITapGestureRecognizer *)tapRecognizer
{
// 3. Find out wich row was tapped (idea based on https://stackoverflow.com/a/25719326)
if (tapRecognizer.state == UIGestureRecognizerStateEnded) {
CGFloat rowHeight = [self.pickerView rowSizeForComponent:0].height;
CGRect selectedRowFrame = CGRectInset(self.pickerView.bounds, 0.0, (CGRectGetHeight(self.pickerView.frame) - rowHeight) / 2.0 );
BOOL userTappedOnSelectedRow = (CGRectContainsPoint(selectedRowFrame, [tapRecognizer locationInView:self.pickerView]));
if (userTappedOnSelectedRow) {
NSInteger selectedRow = [self.pickerView selectedRowInComponent:0];
NSUInteger index = [self.selectedArray indexOfObject:[NSNumber numberWithInteger:selectedRow]];
if (index != NSNotFound) {
NSLog(@"Row %ld OFF", (long)selectedRow);
[self.selectedArray removeObjectAtIndex:index];
} else {
NSLog(@"Row %ld ON", (long)selectedRow);
[self.selectedArray addObject:[NSNumber numberWithInteger:selectedRow]];
}
// I don't know why calling reloadAllComponents sometimes scrolls to the first row
//[self.pickerView reloadAllComponents];
// This workaround seems to work correctly:
self.pickerView.dataSource = self;
NSLog(@"Rows reloaded");
}
}
}
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
// 4. Customize your Picker row as needed.
// This is a very simple view just to make the point
UILabel *pickerLabel = (UILabel *)view;
if (pickerLabel == nil) {
pickerLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 400, 32)];
}
BOOL isSelected = [self.selectedArray indexOfObject:[NSNumber numberWithInteger:row]] != NSNotFound;
NSString *text = [self.dataArray objectAtIndex:row];
text = [text stringByAppendingString:isSelected ? @"☒ " : @"☐ "];
[pickerLabel setText:text];
return pickerLabel;
}
// Do not forget to add the remaining methods to conform the UIPickerViewDataSource and UIPickerViewDelegate protocols!
@end