我想在 UIPickerView 中选择多行,所以我想在一个表中显示我的数据并将这个表作为子视图添加到选择器。我已经尝试过了,但没有成功。
任何建议如何做到这一点?
我想在 UIPickerView 中选择多行,所以我想在一个表中显示我的数据并将这个表作为子视图添加到选择器。我已经尝试过了,但没有成功。
任何建议如何做到这一点?
You can do it without UITableView, using just UITapGestureRecognizer :)
Also, add NSMutableArray *selectedItems
somewhere in your .h file.
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view {
UITableViewCell *cell = (UITableViewCell *)view;
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
[cell setBackgroundColor:[UIColor clearColor]];
[cell setBounds: CGRectMake(0, 0, cell.frame.size.width -20 , 44)];
UITapGestureRecognizer *singleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(toggleSelection:)];
singleTapGestureRecognizer.numberOfTapsRequired = 1;
[cell addGestureRecognizer:singleTapGestureRecognizer];
}
if ([selectedItems indexOfObject:[NSNumber numberWithInt:row]] != NSNotFound) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
} else {
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
cell.textLabel.text = [datasource objectAtIndex:row];
cell.tag = row;
return cell;
}
- (void)toggleSelection:(UITapGestureRecognizer *)recognizer {
NSNumber *row = [NSNumber numberWithInt:recognizer.view.tag];
NSUInteger index = [selectedItems indexOfObject:row];
if (index != NSNotFound) {
[selectedItems removeObjectAtIndex:index];
[(UITableViewCell *)(recognizer.view) setAccessoryType:UITableViewCellAccessoryNone];
} else {
[selectedItems addObject:row];
[(UITableViewCell *)(recognizer.view) setAccessoryType:UITableViewCellAccessoryCheckmark];
}
}
实现了一个快速的 hack 来获得 UIPickerView 多选择行为(如在 Mobile Safari 中)而不在 pickerview 前面添加其他视图,如果有人感兴趣的话:https ://github.com/alexleutgoeb/ALPickerView
高度赞赏改进!
以下代码适用于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
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return true;
}
而且你需要重写这个方法,其他形式的 ios9,点击手势识别将不起作用。
在这种情况下,swift 4 中的相同解决方案
//set up tap gesture
let tapGestureRecognaizer = UITapGestureRecognizer(target: self, action: #selector(pickerTapp))
tapGestureRecognaizer.delegate = self
tapGestureRecognaizer.numberOfTapsRequired = 2
self.pickerView.addGestureRecognizer(tapGestureRecognaizer)
@objc func pickerTapp(tapGesture: UITapGestureRecognizer) {
if tapGesture.state == .ended {
// looking for frame selection row
let selectedItem = dataSource2[pickerView.selectedRow(inComponent: 1)]
let rowHeight = self.pickerView.rowSize(forComponent: 1).height
let rowWidth = self.pickerView.rowSize(forComponent: 1).width
let selectRowFrame = CGRect(x: CGFloat(Int(self.pickerView.frame.width) / self.pickerView.numberOfComponents), y: (self.pickerView.frame.height - rowHeight) / 2, width: rowWidth, height: rowHeight)
let userTappedOnSelectedRow = selectRowFrame.contains(tapGesture.location(in: self.pickerView))
// if tap to selection row ....
if userTappedOnSelectedRow {
if selectedArray.contains(selectedItem) {
var index = 0
for item in selectedArray {
if item == selectedItem {
selectedArray.remove(at: index)
} else {
index += 1
}
}
} else {
selectedArray.append(selectedItem)
}
}
//reload Data
self.pickerView.dataSource = self
self.pickerView.selectRow(selectedRow, inComponent: 1, animated: false)
self.pickerView(self.pickerView, didSelectRow: selectedRow, inComponent: 1)
}
这是我对这个问题的看法:https ://github.com/aselivanov/UIMultiPicker 。我想要与移动 Safari 用来处理<select multiple>
. 它看起来非常相似UIPickerView
(我敢打赌他们共享相同的代码)。