Iphone UIPickerView中的多行选择

Iphone UIPickerView中的多行选择,iphone,uipicker,uitableview,Iphone,Uipicker,Uitableview,我想在UIPickerView中选择多行,所以我想在表中显示我的数据,并将此表作为子视图添加到选择器中。我试过了,但没有成功 有什么建议吗?实施了一个快速破解,以获得UIPickerView多选行为(如在Mobile Safari中),而无需在pickerview前面添加其他视图,如果有人感兴趣: 非常感谢您的改进 您可以在不使用UITableView的情况下完成,只需使用UITapGestureRecognitizer:) 另外,在.h文件的某个地方添加NSMutableArray*selec

我想在UIPickerView中选择多行,所以我想在表中显示我的数据,并将此表作为子视图添加到选择器中。我试过了,但没有成功


有什么建议吗?

实施了一个快速破解,以获得UIPickerView多选行为(如在Mobile Safari中),而无需在pickerview前面添加其他视图,如果有人感兴趣:


非常感谢您的改进

您可以在不使用UITableView的情况下完成,只需使用UITapGestureRecognitizer:)

另外,在.h文件的某个地方添加
NSMutableArray*selectedItems

- (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];
    }
}

您需要覆盖此方法,否则从ios9,点击手势识别将不起作用。

以下代码适用于IOS10。我没有机会在旧版本上测试它,但我认为它应该可以工作。这个想法与@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
//1。符合UIgestureRecognitzerDelegate协议
@接口MyViewController()
@属性(非原子,强)NSMutableArray*selectedArray;//存储选定的行的步骤
@属性(非原子,强)NSArray*dataArray;//选择器数据
@属性(弱,非原子)IBUIPickerView*pickerView;
@结束
@MyViewController的实现
-(无效)viewDidLoad
{    
[超级视图下载];
self.selectedArray=[NSMutableArray];
self.dataArray=@[@“选项1”、@“选项2”、@“选项3”、@“选项4”];
//2.将点击识别器添加到选择器视图
UITapGestureRecognizer*tapRecognizer=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(pickerTapped:)];
tap recognizer.delegate=self;
[self.pickerView addgestureRecognitizer:TapRecognitizer];
}
-(BOOL)手势识别器:(UIGestureRecognizer*)手势识别器应与gestureRecognizer:(UIGestureRecognizer*)其他手势识别器同时识别
{
返回true;
}
-(无效)选取器上限:(UITapGestureRecognitor*)TapRecognitor
{
//3.找出哪一行被点击(想法基于https://stackoverflow.com/a/25719326) 
如果(tapRecognizer.state==UIGestureRecognizerStateEnded){
CGFloat rowHeight=[self.pickerView rowSizeForComponent:0]。高度;
CGRect selectedRowFrame=CGRectInset(self.pickerView.bounds,0.0,(CGRectGetHeight(self.pickerView.frame)-rowHeight)/2.0);
BOOL userTappedOnSelectedRow=(CGRectContainsPoint(selectedRowFrame,[tapcrecognizer locationInView:self.pickerView]);
如果(用户点击选择箭头){
NSInteger selectedRow=[self.pickerView SelectedRowUncomponent:0];
NSInteger索引=[self.selectedArray indexOfObject:[NSNumber numberWithInteger:selectedRow]];
如果(索引!=NSNotFound){
NSLog(@“行%ld关闭”,(长)已选择显示);
[自选阵列移除对象索引:索引];
}否则{
NSLog(@“行%ld在”,(长)已选择显示);
[self.selectedArray addObject:[NSNumber numberWithInteger:selectedRow]];
}
//我不知道为什么调用reloadAllComponents有时会滚动到第一行
//[self.pickerView重载所有组件];
//此解决方案似乎工作正常:
self.pickerView.dataSource=self;
NSLog(@“重新加载的行”);
}
}
}
-(UIView*)pickerView:(UIPickerView*)pickerView视图for行:(NSInteger)行for组件:(NSInteger)组件重用视图:(UIView*)视图
{    
//4.根据需要自定义选择器行。
//这是一个非常简单的观点
UILabel*选择器标签=(UILabel*)视图;
if(pickerLabel==nil){
pickerLabel=[[UILabel alloc]initWithFrame:CGRectMake(0.0,0.0400,32)];
}
BOOL isSelected=[self.selectedArray indexOfObject:[NSNumber numberWithInteger:行]]!=NSNotFound;
NSString*text=[self.dataArray objectAtIndex:row];
text=[text stringByAppendingString:isSelected?@”☒ " : @"☐ "];
[pickerLabel setText:text];
返回选择器标签;
}
//不要忘记添加其余方法以符合UIPickerViewDataSource和UIPickerViewDelegate协议!
@结束

swift 4中对该问题的解决方法相同


完全解决:

我对这个问题的看法是:。我想要的选择器与mobile Safari处理
时使用的选择器完全相同。它看起来非常类似于
UIPickerView
(我打赌它们共享相同的代码).

在本例中,您从未设置过recognizer.view.tag。可能需要修改它。我有三个选择器,并且我只需要一个选择器的这种多重选择。对于其他选择器,我应该返回什么?您可以返回UITableViewCell,但不添加手势识别器。这看起来很流畅,但似乎对我不起作用。我无法获得调用我的方法的识别器。似乎没有收到点击。有人让它工作了吗?iOS 7。嗨,Suda,在iOS 7中,切换选择方法未调用,所以请帮助我为什么未调用gestureDelegate?有什么想法吗?请使用代码格式(4个空格)在你的代码示例之前,为了让你的答案更清晰,Romg!非常感谢你,man@Paglian!你救了我一天!我在想如何在调用reloadAllComponent时禁用滚动条5个小时!而你只需一行代码就可以救我一天!请在你的实际答案中给出问题的解决方案。如果链接的网站改变了你的答案不幸的是,我们将变得毫无用处。
// 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
  //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)
    }