2010-05-25 40 views
13

Quiero seleccionar varias filas en un UIPickerView, así que tuve la idea de mostrar mis datos en una tabla y agregar esta tabla como subvista al selector. Lo he intentado pero no tuve éxito.Selección de varias filas en UIPickerView

¿Alguna sugerencia de cómo hacer esto?

Respuesta

12

la interfaz de usuario "aceptada" para la selección múltiple en el iPhone es usar una UITableView con marcas de verificación (es decir, no use UIPickerView para la selección múltiple).

Sin embargo, si debe hacerlo, hay instrucciones sobre cómo falsificarlo aquí http://www.iphonedevsdk.com/forum/iphone-sdk-development/14634-uipickerview-multiple-selection.html haciendo un selector vacío y poniendo una vista de tabla sobre la parte superior.

+0

Gracias, realmente me ayuda. Mi problema está resuelto Muchas gracias. – Jack

+0

en ese caso, debe aceptar esta respuesta [haga clic en la marca de verificación] (y tal vez volver sobre otra de sus preguntas y hacer lo mismo!) – Andiih

7

implementado un truco rápido para obtener la selección múltiple en el comportamiento UIPickerView (como en Mobile Safari) sin añadir otros puntos de vista frente a la pickerview, si alguien está interesado: https://github.com/alexleutgoeb/ALPickerView

Las mejoras son muy apreciados!

14

Usted puede hacerlo sin UITableView, utilizando sólo UITapGestureRecognizer :)

Además, agregue NSMutableArray *selectedItems en algún lugar de su archivo .h.

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

En este ejemplo, nunca configuró el recognizer.view.tag. Quizás necesite ser revisado –

+0

Tienes razón. Está arreglado ahora. – suda

+2

Tengo tres selectores y necesito este tipo de selección múltiple para un solo selector ... ¿Qué debo devolverle a otros recolectores? – Mano

1
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 
{ 
     return true; 
} 

y hay que reemplazar este método, otra cosa formar ios9, recognization grifo gesto no funcionaría.

+0

utilice el formato de código (4 espacios) antes de su ejemplo de código, para hacer su respuesta más clara –

2

El siguiente código funciona para iOS 10. No tuve la oportunidad de probarlo en versiones anteriores, pero creo que debería funcionar. La idea es similar a la de @ suda pero agrega un único reconocedor de tap directamente a la vista del selector en lugar de agregar el reconocedor de tap a cada fila, ya que esto no funciona en iOS7 +.

Para abreviar, no incluí la implementación completa de los protocolos UIPickerViewDataSource y UIPickerViewDelegate, solo las partes relevantes para implementar la selección múltiple.

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

¡OMG! muchas gracias hombre @Paglian! ¡Salvaste mi día! ¡Se me ha planteado cómo desactivar las volutas mientras llamo a reloadAllComponent durante 5 horas! ¡¡Y me salvaste con solo 1 línea de código !!!!!! – KTang